Clasificación de torneo



Continuamos familiarizándonos con una variedad de montones y algoritmos de clasificación utilizando estos montones. Hoy tenemos el llamado árbol de torneos.
Software EDISON - desarrollo web
EDISON .




, . , .



computer science ;-)
La idea principal de la clasificación de torneos es usar un montón auxiliar relativamente pequeño (en comparación con la matriz principal), que actúa como una cola prioritaria. En este montón, se comparan los elementos en los niveles más bajos, como resultado de lo cual los elementos más pequeños (en este caso, el árbol MIN-HEAP) suben, y el mínimo actual de la parte de los elementos de la matriz que caen en este montón aparece en la raíz. El mínimo se transfiere a una matriz adicional de "ganadores", como resultado de lo cual el montón compara / mueve los elementos restantes, y ahora hay un nuevo mínimo en la raíz del árbol. Tenga en cuenta que con un sistema de este tipo, el siguiente mínimo es mayor en valor que el anterior; luego, se ensambla fácilmente una nueva matriz ordenada de "ganadores", donde simplemente se agregan nuevos mínimos al final de la matriz adicional.



Mover los mínimos a una matriz adicional lleva al hecho de que aparecen vacantes en el montón para los siguientes elementos de la matriz principal, como resultado de lo cual todos los elementos se procesan en el orden de la cola.



La principal sutileza es que además de los "ganadores" también hay "perdedores". Si algunos elementos ya se han transferido al conjunto de "ganadores", entonces si los elementos no procesados ​​son más pequeños que estos "ganadores", entonces no tiene sentido separarlos a través del árbol del torneo en esta etapa; insertar estos elementos en el conjunto de "ganadores" será demasiado costoso (en No puede finalizarlos, pero para ponerlos al principio, debe cambiar los mínimos previamente insertados). Dichos elementos que no lograron encajar en el conjunto de "ganadores" se envían al conjunto de "perdedores": pasarán por el árbol del torneo en una de las siguientes iteraciones, cuando todas las acciones se repitan para los perdedores restantes.



No es fácil encontrar una implementación de este algoritmo en Internet, pero se encontró una implementación clara y agradable en Ruby en YouTube. El código Java también se menciona en la sección "Enlaces", pero no parece tan legible allí.



  #         
  require_relative "pqueue"
	
  #     
  MAX_SIZE = 16

  def tournament_sort(array)
    #   ,   ""
    return optimal_tourney_sort(array) if array.size <= MAX_SIZE
    bracketize(array) #   ,   ""
  end
	
  #     
  def bracketize(array)
	
    size = array.size
    pq = PriorityQueue.new
    #    
    pq.add(array.shift) until pq.size == MAX_SIZE
    winners = [] #  ""
    losers = [] #  ""
		
    #      
    until array.empty?
			
      #  ""  ?
      if winners.empty?
        #      ""
        winners << pq.peek
        #     
        pq.remove 
      end
			
      #      ,   ""
      if array.first > winners.last
        pq.add(array.shift) #       
      else #        ""
        losers << array.shift #     ""
      end
			
      #     ,     ""
      winners << pk.peek unless pk.peek.nil?
      pq.remove #     
			
    end
		
    #   ,      - ?
    until pq.heap.empty?
      winners << pq.peek #     ""
      pq.remove #     
    end

    #   ""  , , ,
    #  "" -   
    return winners if losers.empty?
		
    #    ,    ""
    #   ""
    array = losers + winners
    array.pop while array.size > size
    bracketize(array) #   
		
  end
	
  #       
  def optimal_tourney_sort(array)
    sorted_array = [] #    
    pq = PriorityQueue.new
    array.each { |num| pq.add(num) } #     -
    until pq.heap.empty? #  -  
      sorted_array << pq.heap[0] 
      pq.remove #     
    end
    sorted_array #  
  end
	
  # 
  if $PROGRAM_NAME == __FILE__
    #  
    shuffled_array = Array.new(30) { rand(-100 ... 100) }
    #   
    puts "Random Array: #{shuffled_array}"
    #   
    puts "Sorted Array: #{tournament_sort(shuffled_array)}"
  end


Esta es una implementación ingenua, en la que después de cada división en "perdedores" y "ganadores", estos conjuntos se combinan y luego, para el conjunto combinado, todas las acciones se repiten nuevamente. Si en la matriz combinada hay elementos "perdedores" primero, luego examinar el montón de torneos los ordenará junto con los "ganadores".





Esta implementación es bastante simple e intuitiva, pero no se puede llamar efectiva. Los "ganadores" ordenados pasan varias veces por el árbol del torneo, lo que obviamente es redundante. Supongo que la complejidad del tiempo aquí es log-cuadrática, O ( n log 2 n ) .



Opción de combinación de múltiples rutas



El algoritmo se acelera notablemente si los elementos ordenados que pasan por el tamiz no se pasan repetidamente por las carreras del torneo.



Después de que la matriz desordenada se divide en "ganadores" ordenados y "perdedores" sin clasificar, todo el proceso se repite solo para los "perdedores". En cada nueva iteración, se acumulará un conjunto de matrices con "ganadores" y esto continuará hasta que en algún momento no queden "perdedores". Después de eso, todo lo que queda es fusionar todas las matrices de "ganadores". Como todas estas matrices están ordenadas, esta fusión se realiza con un mínimo esfuerzo.





De esta forma, el algoritmo ya puede encontrar una aplicación útil. Por ejemplo, si tiene que trabajar con big data, a lo largo del proceso de uso del montón de torneos, se lanzarán paquetes de datos ordenados con los que ya puede hacer algo mientras se procesa todo lo demás.



Cada uno de los n elementos de la matriz pasa por el árbol de torneos solo una vez, lo que lleva tiempo O (log n ) . En esta implementación, el algoritmo tiene la complejidad de tiempo peor / promedio O ( n log n ) .



En el final de temporada



Una serie de artículos sobre la clasificación del montón está casi completa. Queda por hablar sobre el más efectivo de ellos.



Enlaces



Tournament sort



Priority queue



Tournament sort in Java



The Theory Behind the The Theory Behind the z/Architecture Sort Assist Instructions



Using Tournament Trees to Sort



Tournament Sort Demo Ruby



Tournament Sort Visualization



Tournament Sort Data Structure UGC NET DS



Tournament Sort Algorithm — a Heapsort variant



:






La clasificación de hoy se ha agregado a la aplicación AlgoLab, que la usa: actualice el archivo de Excel con macros.



En los comentarios a la celda con el nombre de clasificación, puede especificar algunas configuraciones.

La forma variable es un árbol de torneo de múltiples vías (por si acaso, es posible hacer que este árbol no solo sea binario, sino también ternario, cuaternario y pentario).

La variable de cola es el tamaño de la cola inicial (el número de nodos en el nivel más bajo del árbol). Como los árboles están llenos, si, por ejemplo, con way = 2, especifique cola = 5, entonces el tamaño de la cola aumentará a la potencia más cercana de dos (en este caso, hasta 8).

Variable NWayMerge toma el valor 1 o 0; con la ayuda de este se indica si se debe usar la combinación de múltiples rutas o no.



All Articles