C#, cálculo numérico: método de cálculo y programa de origen de Heap Select

1 Breve introducción

HeapSelect es un algoritmo para seleccionar el K-ésimo elemento más grande en una matriz. Es una variante del problema de selección que consiste en encontrar un elemento específico en un conjunto desordenado o parcialmente ordenado.

Esquema del algoritmo: la matriz se convierte en un montón máximo, luego el nodo raíz se elimina repetidamente y se reemplaza con el siguiente elemento más grande hasta que se encuentra el K-ésimo elemento más grande.

2 Heapselect


Vimos un algoritmo aleatorio con la comparación n + O (log n) esperada. ¿Podemos obtener el mismo rendimiento de un algoritmo no aleatorio?
Piensa en los torneos de baloncesto en los que participan n equipos. Formamos un árbol binario completo con n hojas; cada nodo interno representa un juego de eliminación. Entonces, en el nivel inferior, hay n/2 juegos, y los n/2 ganadores pasan a un juego en el siguiente nivel del árbol. Suponiendo que el mejor equipo siempre gana su juego, el mejor equipo siempre gana todos sus juegos y puede encontrarse como el ganador del último juego.

(Todo esto podría expresarse fácilmente en pseudocódigo. Hasta ahora, es solo un algoritmo complicado para encontrar un mínimo o un máximo, que tiene algunas ventajas prácticas, a saber, que es paralelo (se pueden jugar muchos juegos a la vez) y justo (en contraste , si usáramos el algoritmo min anterior, los equipos colocados antes en L tendrían que jugar muchos más juegos y estar en gran desventaja).

Ahora, ¿en qué parte del árbol podría estar el segundo mejor equipo? Este equipo siempre vencería a todos excepto al eventual ganador. Pero debe haber perdido una vez (ya que solo el ganador general nunca pierde). Así que debe haber perdido ante el eventual ganador. Por lo tanto, es uno de los equipos log n que jugó el eventual ganador y podemos ejecutar otro algoritmo de torneo entre estos valores.

Si expresamos esto como un algoritmo para encontrar el segundo mejor, usa solo comparaciones n + ceil(log n), incluso mejor que el algoritmo de caso promedio anterior.

Si lo piensa, el torneo de eliminación descrito anteriormente es similar en algunos aspectos a un montón binario. Y el proceso de encontrar el segundo mejor (repasando los equipos que jugaron contra el ganador) es similar al proceso de quitar el mínimo de un montón. Por lo tanto, podemos usar montones para extender la idea a otros valores pequeños de k:

    heapselect(L,k)
    {     heap H = heapify(L)     for (i = 1; i < k; i++) remove min(H)     return min(H)     } El tiempo es obviamente O(n + k log n), entonces si k = O(n/log n), el resultado es O(n). Lo cual es interesante, pero aún no ayuda para encontrar la mediana.




3 programa fuente C#

utilizando el sistema;

espacio de nombres Legalsoft.Truffer
{     public class Heapselect     {         private int m { get; colocar; }         privado int n { obtener; colocar; }         privado int srtd { obtener; colocar; }         montón privado doble [] { obtener; colocar; }





        Heapselect público (int mm)
        {             this.m = mm;             esto.n = 0;             esto.srtd = 0;             this.heap = new double[mm];             for (int i = 0; i < mm; i++)             {                 heap[i] = 1.0E99;             }         }








        public void add(doble val)
        {             if (n < m)             {                 heap[n++] = val;                 if (n == m)                 {                     Array.Sort(montón);                 }             }             else             {                 if (val > heap[0])                 {                     heap[0] = val;                     para (int j = 0; ;)                     {                         int k = (j << 1) + 1;                         si (k > m - 1)                         {                             descanso;



















                        }
                        if (k != (m - 1) && montón[k] > montón[k + 1])
                        {                             k++;                         }                         if (montón[j] <= montón[k])                         {                             ruptura;                         }                         Globals.SWAP(montón de referencia[k], montón de referencia[j]);                         j = k;                     }                 }                 n++;             }             srtd = 0;         }













        informe doble público (int k)
        {             int mm = Math.Min (n, m);             if (k > mm - 1)             {                 throw new Exception("Heapselect k too big");             }             if (k == m - 1)             {                 return heap[0];             }             if (srtd == 0)             {                 Array.Sort(montón);                 serie = 1;             }             devolver montón[mm - 1 - k];         } }     }


















 

4 Código C de referencia

/***********************************************************************
 * Author: Isai Damier
 * Title: Find the Greatest k values
 * Project: geekviewpoint
 * Package: algorithms
 *
 * Statement:
 *   Given a list of values, find the top k values.
 *
 * Time Complexity: O(n log n)
 * 
 * Sample Input: {21,3,34,5,13,8,2,55,1,19}; 4
 * Sample Output: {19,21,34,55}
 * 
 * Technical Details: This selection problem is a classic and so has
 *   many very good solutions. In fact, any sorting algorithm can be
 *   modified to solve this problem. In the worst case, the problem
 *   can indeed be reduced to a sorting problem: where the collection
 *   is first sorted and then the element at indices 0 to k-1 are
 *   retrieved.
 *   
 *   Presently the problem is solved using a modified version of
 *   heapsort called heapselect.
 **********************************************************************/
 public int[] heapselectTopK(int[] G, int k) {
  int last = G.length - 1;
  //convert array to heap in O(n)
  int youngestParent = last / 2;//l = 2*p+1: p=(l-1)/2
  for (int i = youngestParent; i >= 0; i--) {
    moveDown(G, i, last);
  }
  //sort up to k (i.e. find the kth)
  int limit = last - k;
  for (int i = last; i > limit; i--) {
    if (G[0] > G[i]) {
      swap(G, 0, i);
      moveDown(G, 0, i - 1);
    }
  }
  return Arrays.copyOfRange(G, G.length - k, G.length);
}
 
private void moveDown(int[] A, int first, int last) {
  int largest = 2 * first + 1;
  while (largest <= last) {
    if (largest < last && A[largest] < A[largest + 1]) {
      largest++;
    }
    if (A[first] < A[largest]) {
      swap(A, first, largest);
      first = largest;
      largest = 2 * first + 1;
    } else {
      return;
    }
  }
}

Supongo que te gusta

Origin blog.csdn.net/beijinghorn/article/details/132051642
Recomendado
Clasificación