【Registro de aprendizaje de estructura de datos 27】 —— Seleccione Ordenar y Ordenar montón

1. Orden de selección

1. Principio

La selección y ordenación es relativamente simple, es decir, después de cada recorrido, se intercambia un valor máximo (mínimo) del área desordenada con el primer o último valor del área desordenada. De esta manera, el área desordenada se ordena gradualmente, y finalmente Complete la clasificación. Su complejidad de tiempo también es O (n 2) O (n ^ 2)O ( n2 )

2. Proceso

Inserte la descripción de la imagen aquí

3. Código

int selectsort(int arry[], int len)
{
    
    
    int min, i, j, temp;

    for(i = 0; i < len - 1; ++i)
    {
    
    
        min = i;
        for (j = i; j < len; ++j)
        {
    
    
            if (arry[j] < arry[min])
            {
    
    
                min = j;
            }
        }
        temp = arry[i];
        arry[i] = arry[min];
        arry[min] = temp;
    }
}

2. Orden de montón

1. El concepto de montón

Suponga que la secuencia k 1, k 2, ⋅ ⋅ ⋅, kn (k_1, k_2, \ cdot \ cdot \ cdot, k_n)k1,k2,,knHay y solo cuando se cumplen las siguientes relaciones, lo llamamos un montón:
{ki ≤ k 2 i, ki ≤ k 2 i + 1 o {ki ≥ k 2 i, ki ≥ k 2 i + 1 donde (i = 1, 2, ⋅ ⋅ ⋅, n 2) \ begin {cases} k_i ≤ k_ {2i}, \\ k_i ≤ k_ {2i + 1} \ end {cases} o \ begin {cases} k_i ≥ k_ {2i} , \ \ k_i ≥ k_ {2i + 1} \ end {cases} donde (i = 1,2, \ cdot \ cdot \ cdot, \ frac {n} {2}){ kyok2 yo,kyok2 yo + 1o{ kyok2 yo,kyok2 yo + 1Que el ( yo=1 ,2 ,,2n)
Tenga en cuenta que el número de secuencia comienza en 1.
El primero es menor o igual que la relación, por eso también lo llamamos: el 小根堆
segundo es mayor o igual que la relación, por eso también lo llamamos:大根堆

2. La relación entre el montón y el árbol binario completo

Luego, si simulamos un árbol binario completo a través de esta secuencia (matriz), debajo de la estructura del árbol, el montón tiene las siguientes propiedades:
cada nodo padre es más grande (menor que) su nodo hijo, vea la imagen:
suponga que existe esta raíz pequeña montón:
Inserte la descripción de la imagen aquí

Para "convertirlo" en un árbol binario completo:
Inserte la descripción de la imagen aquí
No es difícil ver que los nodos secundarios del nodo n son 2n y 2n + 1

3. El proceso de clasificación de pilas

Ahora sabemos que el nodo raíz de este árbol binario de montón (simulado por secuencia secuencial) debe estar 最大(小), entonces el elemento debe estar en un estado ordenado. Entonces nuestra idea de clasificación debería ser:

  1. Construye un montón
  2. Excluir el elemento del nodo raíz (excluir el elemento superior o intercambiar con el último elemento y excluir)
  3. Reajuste la estructura para que los elementos restantes formen una pila.
  4. Repita 2 y 3 hasta que todos los elementos estén en orden

Por supuesto, en el segundo punto, para evitar que se destruya la estructura básica del árbol, elegimos colocar el elemento superior y el elemento final 交换después del elemento superior del pilote , y clasificamos el elemento final como 有序区, es decir, excluir y no participar en el reajuste de la estructura del punto 3..
Por lo tanto, sobre esta base, generalmente usamos el orden ascendente 大根堆y el orden descendente 小根堆.
Después de una derivación complicada, su complejidad de tiempo es O (nlog 2 n) O (nlog_2n)O ( n l o g2n )

4. Construye un montón

Para inicializar el montón, necesitamos los siguientes pasos:
Realice las siguientes 调整堆operaciones en todos los nodos principales :

  1. Si los nodos secundarios son todos más pequeños que el nodo principal, finaliza.
  2. En el caso de no 1: se intercambia el valor máximo del nodo padre y el nodo hijo, y las operaciones de 1 y 2 se realizan en el nodo hijo después del intercambio.

Sabemos que asumiendo un árbol binario completo lleno de hojas, supongamos que tiene n nodos, entonces el número de nodos de hojas es (n + 1) 2 \ frac {(n + 1)} {2}2( N + 1 ), Entonces el nodo padre tiene (n - 1) 2 \ frac ((n-1)) (2)2( N - 1 )Uno
Luego, suponga que inicializamos el montón, comenzamos desde el último nodo padre y avanzamos (de derecha a izquierda, de abajo hacia arriba) para construir el montón en un bucle.
Desde el punto de vista del código:

    // 从最后一个父结点开始,将所有结点给调整一次。
    for (i = len/2; i > 0; --i)
    {
    
    
        HeapAdjust(heapArry, i, len);
    }

5. Ajustar el montón

Ajustamos el montón, pensamientos y dijimos:

  1. Si los nodos secundarios son todos más pequeños que el nodo principal, finaliza.
  2. En el caso de no 1: se intercambia el valor máximo del nodo padre y el nodo hijo, y las operaciones de 1 y 2 se realizan en el nodo hijo después del intercambio.

el código se muestra a continuación:

int HeapAdjust(int arry[], int index, int len)
{
    
    
    int i;
    arry[0] = arry[index]; // arry[0] 没被使用,刚好可以拿来当交换时的临时变量用
    for (i = 2*index; i <= len; i*=2)   // 从该结点的左孩子开始,且每次循环都直接到孩子的孩子,且i肯定不能超过树的大小
    {
    
    
        if (i < len && arry[i] < arry[i+1]) // 这里是判断i当前孩子是左孩子大还是右孩子大,将i指向最大的孩子
        {
    
    
            ++i;
        }
        // 把上者<改成>,下者>=改为<=,则该堆排序变成降序
        if (arry[0] >= arry[i]) // 如果我们的处理的结点大于了孩子结点,那么就必须交换。
        {
    
    
            break;
        }
        else
        {
    
    
            arry[index] = arry[i];  // 我们处理的结点被孩子顶替
            index = i;              // 我们新处理的结点变成了被顶替的孩子位置
        }
    }
    arry[index] = arry[0];  // 一直到了最后,孩子一直顶替,直到没法顶替了,就是我们最开始待处理结点的位置
}

Leyenda:
Supongamos que solo tenemos el nodo raíz sin ajustar, ahora necesitamos ajustar el nodo con índice = 1:
Inserte la descripción de la imagen aquí
primero ingrese y determine el estado de nuestro elemento: 5 se debe ajustar, 7 es el punto actual para el hijo:
Inserte la descripción de la imagen aquí
en este tiempo, [0] <[i], es decir, 5 <7, porque debería haber un ajuste, por lo que [1] debería ser igual a [2], y luego el valor a ajustar ha cambiado de [1] a [2], y el hijo puntiagudo ha cambiado a [4]]:
Inserte la descripción de la imagen aquí
En este momento, [0] <[i], es decir, 5 <6, porque debería producirse el ajuste, por lo que [2] debería ser igual a [4 ], y luego el ajuste que se va a ajustar ha cambiado de [2] a [4], apuntando a El hijo de ha cambiado a [8] (no existe):
Inserte la descripción de la imagen aquí

Luego, después de salir del bucle, hemos determinado la posición que se va a ajustar index = 4, por lo que temp es el valor de arry [0] a arry [4]:
Inserte la descripción de la imagen aquí

Esto completa un ajuste de montón.

6. Código

Para el proceso específico, puede generar HeapSort a la mitad para ver el proceso de clasificación y construcción del montón.

#include <stdio.h>
#include <stdlib.h>

int HeapAdjust(int arry[], int index, int len)
{
    
    
    int i;
    arry[0] = arry[index]; // arry[0] 没被使用,刚好可以拿来当交换时的临时变量用
    for (i = 2*index; i <= len; i*=2)   // 从该结点的左孩子开始,且每次循环都直接到孩子的孩子,且i肯定不能超过树的大小
    {
    
    
        if (i < len && arry[i] < arry[i+1]) // 这里是判断i当前孩子是左孩子大还是右孩子大,将i指向最大的孩子
        {
    
    
            ++i;
        }
        // 把上者<改成>,下者>=改为<=,则该堆排序变成降序
        if (arry[0] >= arry[i]) // 如果我们的处理的结点大于了孩子结点,那么就必须交换。
        {
    
    
            break;
        }
        else
        {
    
    
            arry[index] = arry[i];  // 我们处理的结点被孩子顶替
            index = i;              // 我们新处理的结点变成了被顶替的孩子位置
        }
    }
    arry[index] = arry[0];  // 一直到了最后,孩子一直顶替,直到没法顶替了,就是我们最开始待处理结点的位置
}

int HeapSort(int arry[], int len)
{
    
    
    int i = 1;

    int *heapArry = (int*)malloc(sizeof(int) * (len+1));    // 构造一个从下标1开始的序列。
    for (i = 1; i <= len; ++i)
    {
    
       
        heapArry[i] = arry[i - 1];
    }

    // 从最后一个父结点开始,将所有结点给调整一次。
    for (i = len/2; i > 0; --i)
    {
    
    
        HeapAdjust(heapArry, i, len);
    }

    // 堆排序。
    for (i = len; i > 0; --i)
    {
    
    
        arry[i-1] = heapArry[1];    // 堆顶是我们的最大元素,赋值给原数组
        heapArry[1] = heapArry[i];  // 因为是交换,所以要把最后一个元素给堆顶,堆顶给最后一个元素(有序),但我们可以舍弃这个保存,因为存到了老数组里
        HeapAdjust(heapArry, 1, i - 1); // i之后的结点是有序的(尽管没有赋值),所以不参与堆的构造
    }
}

int main()
{
    
    
    int a[7] = {
    
    5,6,3,7,2,1,4};
    int i;
    HeapSort(a, 7);
    for (i = 0; i < 7; ++i)
    {
    
    
        printf("%d ", a[i]);
    }
    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/u011017694/article/details/111504356
Recomendado
Clasificación