Método de clasificación de la estructura de datos

1. Orden de inserción directa.
Para insertar el elemento L (i) en la subsecuencia preordenada L (1 ... i-1), se requieren las siguientes operaciones. (L [] se usa a continuación para representar una tabla, y L [] se usa para representar un elemento)
1. Encuentre la posición de inserción k de L (i) en L [1 ... i-1].
2. Mueva todos los elementos en L [k ... i-1] hacia atrás una posición.
3. Copie L (i) a L (k).
Para realizar la clasificación de L [1 ... n], L (2) ~ L (n) se pueden insertar una por una en la subsecuencia organizada previamente. Inicialmente, se supone que L (1) es una subsecuencia.
El siguiente es el algoritmo de código para la ordenación por inserción directa

void InsertSort(ElemType A[],int n){
    
    
    int i,j;
    for(i=2;i<=n;i++)  || 依次将A(2)~A(n)插入到前面已排序序列
        if(A[i].key<A[i-1].key){
    
      ||若A[i]的关键码小于其前驱,需要将A[i]插入有序表
            A[0]=A[i];  ||复制为哨兵,A[0]不存放元素
            for(j=i-1;A[0].key<A[j].key;--j)  ||从后往前找待插入位置
                A[j+1]=A[j];  ||向后挪移
            A[j+1]=A[0];  ||复制到插入位置
        }
}

P.EJ,
Inserte la descripción de la imagen aquí

Dos, medio tipo de inserción.
Se puede ver en el algoritmo de clasificación de inserción directa que se llevan a cabo dos tareas en cada proceso de inserción.
1. Encontrar la posición donde se debe insertar el elemento a insertar de la tabla semilla anterior;
2. Hacer espacio para la posición de inserción y esperar El elemento insertado se copia a la posición de inserción en la tabla.
En el algoritmo de ordenación por inserción directa, los elementos siempre se mueven mientras se comparan. A continuación, se separa la comparación y el movimiento, es decir, primero encuentra la posición de inserción del elemento por la mitad y luego mueve uniformemente todos los elementos después de la posición que se desea insertado, es decir, el tipo de medio inserción.
Debido a que es una tabla lineal almacenada secuencialmente, puede usar una búsqueda binaria para encontrar una subtabla ordenada. El código es el siguiente

void ShellSort (ElemType A[],int n) {
    
    
    int i,j,low,high,mid;
    for(i=2;i<=n;i++) {
    
      ||依次将A(2)~A(n)插入到前面已排序序列
        A[0]=A[i];  ||将A[i]暂存到A[0]
        low=1;high=i-1;  ||设置折半查找的范围
        while(low<=high){
    
      ||折半查找(默认递增有序)![在这里插入图片描述](https://img-blog.csdnimg.cn/20210304015428712.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NDUwMTYzMg==,size_16,color_FFFFFF,t_70#pic_center)

            mid=(low+high)/2;  ||取中间点
            if(A[mid].key>A[0].key) high=mid-1;  ||查找左半子表
            else low=mid+1;  ||查找右半子表
            }
            for(j=i-1;j>=high+1;--j)
                A[j+1]=A[j];  ||统一后移元素,空出插入位置
            A[high+1]=A[0];  ||插入操作
    }
}

P.EJ.
Inserte la descripción de la imagen aquí

3. Clasificación de colinas.
La idea básica de la clasificación Hill es: primero divida la lista que se va a clasificar en varias subtablas "especiales" como L [i, i + d, i + 2d, `` i + kd], e inserte directamente en las subtablas Ordenación, cuando los elementos de la tabla completa están básicamente en orden, luego realice una ordenación de inserción directa en todos los registros. El proceso es el siguiente:
primero tome un tamaño de paso d1 menor que n, divida todos los registros de la tabla en grupos d1, coloque todos los registros con una distancia de múltiplos de d1 en el mismo grupo y realice la ordenación por inserción directa en cada grupo; luego tome el primero Para dos pasos d2 <d1, repita el proceso anterior hasta que el dt obtenido = 1, es decir, todos los registros se hayan colocado en el mismo grupo, y luego realice la clasificación por inserción directa. Debido al buen orden local en este tiempo, por lo tanto, el resultado final se puede obtener rápidamente. Hasta el momento no se ha obtenido la mejor secuencia de incrementos La ciudad propuesta por Hill es d1 = n / 2, di + 1 = [d / 2] y el último incremento es igual a 1.

void ShellSort (ElemType A[],int n){
    
    
    for(dk=n/2;dk>=1;dk=dk/2)  ||步长变化
        for(i=dk+1;i<=n;++i)  
            if[Ai].key<A[i-dk],key){
    
      ||需将 A[i]插入有序增量子表
                 A[0]=A[i];  ||暂存在A[0]
                 for(j=i-dk;j>0&&A[0].key<A[j].key;j-=dk)
                     A[j+dk]=A[j];  ||记录后移,查找插入位置
                 A[j+dk]=A[O];  ||插入
            }
}

P.EJ.
Inserte la descripción de la imagen aquí

Cuarto, clasificación de burbujas.
La idea básica del algoritmo de ordenación es: Suponga que la longitud de la lista a ordenar es n, compare los valores adyacentes por pares de atrás hacia adelante (o de adelante hacia atrás), si está en orden inverso (es decir, A [i-1]> A [i]), luego cámbielos hasta que se complete la comparación de secuencias. Lo llamamos burbujeo y, como resultado, el elemento más pequeño se cambia a la primera posición de la secuencia que se va a ordenar (el elemento con la palabra clave más pequeña "flota" gradualmente hasta la "superficie del agua" como una burbuja). En el siguiente burbujeo, el elemento más pequeño determinado en la pasada anterior ya no participará en la comparación, y la secuencia a ordenar se reducirá en un elemento. El resultado de cada pase de burbujeo coloca el elemento más pequeño en la secuencia al final posición de la secuencia.
El código del algoritmo es el siguiente

void BubbleSort(ElemType A[],int n){
    
    
    for(i=0;i<n-1;i++){
    
     
        flag=false;  ||表示本趟冒泡是否发生交换的标志 
        for(j=n-1;j>i;j--)  ||一趟冒泡过程
            if(A[j-1].key>A[j].key){
    
      ||若为逆序
                  swap (A[j-1],A[j];  ||交换
                  flag=true;
            }
        if(flag==false)
            return ;  ||本趟遍历后没有发生交换,说明表已经有序
     }
} 

P.EJ
Inserte la descripción de la imagen aquí

Cinco, clasificación rápida.
La clasificación rápida es una mejora de la clasificación de burbujas. La idea básica es el método básico de divide y vencerás; cualquier elemento pivote en la lista que se va a ordenar L [1 ... n] se toma como punto de referencia, y la lista que se va a ordenar se divide en dos partes independientes L [ 1 ... k-1 a través de una clasificación] Y L [K + 1 ... n] de modo que todos los elementos en L [1 ... k-1] son ​​menores que pivote, y todos los elementos en L [k + 1 ... n] son ​​mayores o iguales que el pivote, luego el pivote se coloca en
su posición final L En (k), este proceso se denomina clasificación rápida de una pasada. Luego repita de forma recursiva el proceso anterior para las dos sub-tablas hasta que solo haya un elemento en cada parte o vacío, es decir, todos los elementos se coloquen en sus posiciones finales.
La estructura del algoritmo es la siguiente

void QuickSort(ElemType A[],int low,int high){
    
    
    if (low<high)  ||递归跳出的条件
             int pivotpos=Partition (A,low,high);  ||划分
             QuickSort (A, low, pivotpos-1);  ||依次对两个子表进行递归排序
             QuickSort (A,pivotpos+1,high);
    }
}

Suponiendo que el primer sistema de elementos de la tabla actual siempre se usa como valor pivote (referencia) cada vez, los elementos de la tabla que son más grandes que el valor pivote deben moverse hacia la derecha y los elementos más pequeños que el valor pivote debe moverse hacia la izquierda., De modo que después de una operación, los elementos de la tabla se dividan en dos por el valor de pivote.

int Partiion(ElemType A[],int low,int high){
    
    
    ElemType pivot=A[low];  ||将当前表中第一个元素设为枢轴值,对表进行划分
    while (low<high){
    
      ||循环跳出条件
        while(low<high&&A[high]>=pivot) --high; 
        A[low]=A[high];  ||将比枢轴值小的元素移动到左端
        while(low<high&&A[low]<=pivot) ++low;
        A[high]=A[low]||将比枢轴值大的元素移动到右端
    }
    A[low]=pivot;  ||枢轴元素存放到最终位置
    return low;  ||返回存放枢轴的最终位置
}

P.EJ.
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

En sexto lugar, selección y clasificación simples.
La idea de la clasificación por selección simple: asumiendo que la tabla de clasificación es L [1 ... n], la i-ésima clasificación es seleccionar el elemento con la clave más pequeña de L [1 ... n] para intercambiar con L [i], y cada clasificación puede determinar una La posición final del elemento, de modo que toda la clasificación se pueda ordenar después de la clasificación n-1.
El código del algoritmo es el siguiente

void SelectSort(ElemType A[],int n){
    
    
    for(i=0;i<n-1;i++){
    
      ||一共进行 n-1趟
        min=i;  ||记录最小元素位置
        for(j=i+1;j<n;j++)  ||在A[i…n-1]中选择最小的元素 
            if(A[j]<A[min)min=j;  ||更新最小元素位置
        if(min!=i)swap(A[i],A[min];   ||与第i个位置交换
    }
}    

Siete, clasificación en pilas.
La clasificación de pila es un método de clasificación selectiva en forma de árbol. Sus características son: en el proceso de clasificación, L [1 ... n] se considera una estructura de almacenamiento secuencial de un árbol binario completo, y el nodo padre y el nodo hijo en el Se utilizan árbol binario completo La relación interna entre los puntos, seleccione el elemento con la palabra clave más grande (o más pequeña) en el área desordenada actual.
La definición de montón es la siguiente: n secuencia de teclas L [1 ... n] se llama montón, si y solo si la secuencia cumple:
1. L (i) <= L (2i) y L (i) <= L (2i) +1) o 2, L (i)> = L (2i)) y L (i)> = L (2i + 1) (1 <= i <= n / 2])
La pila que pesa que satisface el primer caso Es una pila de raíces pequeña (pila superior pequeña), y una pila que cumple la segunda condición se llama pila de raíces grande (pila superior grande). En la pila raíz grande, el elemento más grande se almacena en el nodo raíz y, para cualquier nodo que no sea raíz, su valor es menor o igual que el valor de su nodo principal. La definición de pilote de raíces pequeño es todo lo contrario, el nodo raíz es el elemento más pequeño.
La clave para la clasificación de montones es construir un montón inicial y construir un montón sobre la secuencia inicial, que es un proceso de selección repetida. Un árbol completo de n nodos, el último nodo es el hijo del [n / 2] ésimo nodo. Filtre el subárbol enraizado en el [n / 2] nodo (para un montón raíz grande: la clave del nodo raíz es más pequeña que la que tiene la clave más grande en los elementos secundarios izquierdo y derecho, luego intercambie), de modo que el subárbol se convierte en un montón. Luego, filtre los subárboles enraizados en cada nodo (n / 2] -1 ~ 1) para ver si el valor del nodo es mayor que el valor de sus nodos secundarios izquierdo y derecho. De lo contrario, sume el izquierdo y el derecho Nodos secundarios. Se intercambia un valor mayor con él, y el siguiente nivel de montón puede destruirse después del intercambio, así que continúe usando el método anterior para construir el siguiente nivel de montón hasta que el subárbol enraizado en este nodo constituya un montón. Utilice repetidamente el método anterior para ajustar la pila para construir la pila hasta el nodo raíz.
El siguiente es el código del algoritmo del gran montón raíz

void BuildMaxHeap(ElemType A[],int Len){
    
    
    forint i=len/2;i>0;i--)
         AdjustDown (A,i,len);
}
void AdjustDown(ElemType A[],int k,int Len){
    
    
    A[0] =A[k];  ||A[0]暂存
    for (i=2*k;i<=len;i*=2){
    
      ||沿 key 较大的子结点向下筛选
         if(i<len&&A[i]<A[i+1])  
             i++;  ||取 key 较大的子结点的下标
         if(A[0]>=A[i]break;  ||筛选结束
         else{
    
    
             A[k]=A[i];  ||将 A[i]调整到双亲结点上
             k=1;  ||修改 k 值,以便继续向下筛选
         }
    }
    A[k]=A[0];  ||被筛选结点的值放入最终位置
}

P.EJ.
Inserte la descripción de la imagen aquí

8. Combinar y ordenar.
"Fusionar" significa combinar dos o dos; secuencia de tabla en una nueva tabla ordenada. Suponiendo que la lista que se va a ordenar contiene n registros, se puede considerar como n subtablas ordenadas con una longitud de 1, y luego fusionarse en pares para obtener [n / 2] listas ordenadas con una longitud de 2 o 1; dos se fusionan.

ElemType *B=(ElemType *)malloc((n+1*sizeof(ElemType)
void Merge(ElemType A[],int low,int mid,int high){
    
    
    for(int k=low; k<=high; k++
        B[k]=A[k];  ||将 A中所有元素复制到 B 中 
    for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
    
    
        if(B [i]<=B[j])  || 比较 B 的左右两段中的元素
             A[k]=B[1++]  ||将较小值复制到A 中 
        else
             A[k]=B[j++];
    }
    while(i<=mid) A[k++]=B[i++];  ||若第一个表未检测完,复制 
    while(i<=high)A[k++]=B[j++];  ||若第二个表未检测完,复制
}

Nota: solo se ejecutará uno de los dos últimos bucles while del código anterior.

P.EJ.Inserte la descripción de la imagen aquí

La siguiente figura es una comparación de la complejidad temporal, la complejidad espacial de cada método de clasificación y si el algoritmo es estable.

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_54501632/article/details/114339914
Recomendado
Clasificación