Fundamentos de la estructura de datos y el algoritmo (Wang Zhuo) (36): Tipo rápido de clasificación de intercambio [Fase 3: Profundizar para resolver problemas] ¡Esencia! ¡Esencia! ¡Esencia! ! ! Decir cosas importantes tres veces

Tabla de contenido

Revisar:

Problemas específicos:

Núcleo operativo:

Nota:

Desglose de la operación:

Implementación de la operación:

Pregunta (1): Hacer juicios si/si no de diferentes momentos

Problema (2): pasar la condición como "elemento más pequeño que el centinela" no funciona

Pregunta 3):

Cuando se usa [mayor que o igual a] como condición de bucle (while), el principio operativo del programa (marco)

en primer lugar

más tarde nos enteramos

¿Creías que finalmente íbamos a terminar aquí?

sin embargo no

el mayor problema:

Al principio (antes), pensábamos:

Y luego descubrimos que en realidad no es tan simple:

problema real:

Concretar el problema en el flujo del programa:

(1):

(2):

El proceso completo de concreción:

(1):

(2):

No se confirma encontrar el siguiente elemento con un espacio en blanco antes de continuar con el siguiente paso (operación de cambio de puntero)

En cambio, siempre que se compare el siguiente elemento, se intercambie el elemento o se mueva el puntero de posición, se realizará el siguiente paso.

Modifique el resultado final de la siguiente manera:

Solo cambiamos la operación del puntero después de estar seguros de encontrar un elemento más grande o más pequeño que el centinela y nos aseguramos de insertar el espacio

Sin embargo, el programa anterior realizará la operación de cambiar el puntero independientemente de si se encuentra o se intercambia.

De hecho, el resultado que queremos modificar es dejar que el programa determine que la operación de insertar espacios se realiza antes de continuar con el siguiente paso (siguiente ronda)

respuesta estándar:


Revisar:

Problemas específicos:

Para el problema del mecanismo lógico operativo, tomemos el ejemplo en el PPT como ejemplo:

Convierta cada operación específica en una tabla y visualícela de la siguiente manera: 

los primeros pasos funcionar Puntos bajos a Puntos altos a
paso 1 49 Cambio Centinela 1 8
paso 2

49' no se mueva, alto-- (el primer juicio si / si no)

1 7
paso 3 49 no se mueve, bajo++ (el segundo juicio si / si no) 2 7


Aquí viene el tercer paso, y obviamente algo sale mal:

Todavía no hay ningún elemento en el espacio, su algoritmo comienza a adelantarlo y saltar al siguiente espacio, ¿por qué?

La repetición es relativamente inofensiva, pero los movimientos bajos, ¡peligrosos! ! ! (yendo mal)

Claramente aquí, podemos ver que el problema es:

Después de colocar el primer elemento procesado en el centinela, comparamos el centinela con el elemento mismo

Es decir, comparándote y perdiendo este espacio;

En lugar de usar este espacio para que quepa el primer elemento más pequeño que el centinela


Núcleo operativo:

Así que lo que tenemos que hacer es:

Desde el comienzo del programa, supervise cada paso de la operación del programa para asegurarse de que:

Ponemos [el espacio que deja el primer elemento] en [el primer elemento más pequeño que el centinela]


Nota:

Monitor:

Para ser más precisos, nuestra llamada "vigilancia" aquí se refiere a reescribir

Comience desde el principio del programa hasta que [el espacio dejado por el primer elemento] se cargue en [el primer elemento más pequeño que el centinela]

Durante este proceso, todos los procedimientos operativos de todo el proceso se reescriben a mano paso a paso.


Desglose de la operación:

Y vamos a (al principio) escribir a mano:

Comience desde el principio del programa hasta que [el espacio dejado por el primer elemento] se cargue en [el primer elemento más pequeño que el centinela]

El funcionamiento de todo el proceso no es más que:

Desde el comienzo del programa, (siempre) compare el puntero alto: (compare el último bit primero)

  1. Si el [puntero alto apunta al elemento] es más pequeño que el centinela, coloque el elemento en el espacio frontal
  2. Si no es menor que (>=):
  • Este elemento se sigue colocando detrás
  • 【puntero alto】Continúe buscando hacia adelante y compare el tamaño del elemento anterior con el centinela

Implementación de la operación:

Pregunta (1): Hacer juicios si/si no de diferentes momentos

Y aquí, si escribimos el programa o seguimos/nos gusta la sección anterior, simplemente usamos la declaración de juicio if/else cada vez, entonces

Nuestra lista para diferentes pedidos:

Indudablemente, se requieren diferentes tiempos de juicios if/else cada vez

(Quién sabe qué tan atrás está el primer elemento más pequeño que el centinela)

Esto es sin duda imposible


Problema (2): pasar la condición como "elemento más pequeño que el centinela" no funciona

Ya que nuestro propósito es encontrar el primer elemento de atrás hacia adelante que sea menor que el centinela

Encuentre directamente este "primer elemento más pequeño que el centinela" en sí

Si la condición de configuración es: buscar directamente a través de [la condición de juicio es "elemento más pequeño que el centinela"]

A menos que el último elemento sea más pequeño que el centinela, es imposible encontrarlo directamente.

Si hay elementos mayores o iguales que el centinela, no podemos cruzarlo en absoluto.

if (low < high && L.r[high].key >= L.r[0].key)
{
    if (low < high && L.r[high].key >= L.r[0].key)
    {
        ...//无数个:
//【if (low < high && L.r[high].key >= L.r[0].key){}     else  把元素放前面空格里面】语句
//根本写不完,实现不了,死循环
    }
    else  把元素放前面空格里面
}
else  把元素放前面空格里面

Por lo tanto, solo podemos establecer la condición del ciclo de juicio para que no sea menor que (>=) centinela


Pregunta 3):

Cuando se usa [mayor que o igual a] como condición de bucle (while), el principio operativo del programa (marco)


en primer lugar

Cuando escribimos algoritmos, damos por sentado que

Cuando se usa [mayor que o igual a] como el ciclo de condición de bucle (while), la estrategia es tomar la siguiente mejor cosa

Asegúrese de encontrar [el elemento anterior menor que (elemento centinela)];

Luego encuentre el elemento por (+1) el elemento anterior del elemento más pequeño que el centinela para la operación


más tarde nos enteramos

No, el proceso de ejecución escrito arriba es el resultado que damos por sentado

De hecho, cuando la condición del bucle se cambia a [mayor o igual que] centinela, la lógica de funcionamiento del programa es:

Si es mayor o igual a: siempre alto--;

hasta encontrar el primer elemento más pequeño que el centinela

Cuando el programa sale del bucle, high ya apunta al elemento al que debemos apuntar al intercambiar

Encontró directamente el "primer elemento más pequeño que el centinela" en sí

en lugar del elemento anterior

Así que haz cambios: 

int 遍历(SqList &L, int low, int high)
{
    L.r[0] = L.r[low];
    while (low < high && L.r[high].key >= L.r[0].key)
        high--;
    L.r[low] = L.r[high];


    while (low < high)
    {
        if (L.r[high].key < L.r[0].key)
        {
            L.r[low] = L.r[high];
            low++;
        }
        else
            high--;
        if (L.r[0].key < L.r[low].key)
        {
            L.r[high] = L.r[low];
            high--;
        }
        else
            low++;
    }
    L.r[low] = L.r[high] = L.r[0];
    return low;
}

void QuickSort(SqList& L, int low, int high)
{
    int pivot = 遍历(L, low, high);
    QuickSort(L, low, pivot-1);
    QuickSort(L, pivot + 1, high);
}

int main()
{
    SqList L;
    cin >> L.length;
    cin >> L.r->key;

    QuickSort(L, 1, L.length);
}

¿Creías que finalmente íbamos a terminar aquí?

sin embargo no


el mayor problema:

Luego, continuamos profundizando y descubrimos que el problema con este programa no es tan simple:

Al principio (antes), pensábamos:

El programa aparece solo porque al principio, debido a que el primer elemento está almacenado en el centinela:

El elemento mismo compara al centinela, es decir, se compara a sí mismo y pierde el espacio;

El error causado por el fenómeno , lo importante es:

Pensamos que este era un caso especial, todo el programa solo tenía un problema al principio

Y luego descubrimos que en realidad no es tan simple:

El problema de que el programa ya apareció al principio (no se puede ordenar correctamente) también existe en el programa posterior (secuencial):

problema real:

Si el espacio antes/después no se ha llenado, comenzamos a mover el puntero antes/después

Entonces este espacio en blanco nunca se volverá a llenar, por lo que (de ahora en adelante), nunca podremos volver atrás y encontrar este espacio en blanco.

Entonces los siguientes procedimientos están todos en mal estado, causando grandes problemas


Concretar el problema en el flujo del programa:

(Procedimiento) El problema real (emergente) es:

No estoy seguro todavía:

(1):

El elemento señalado por el puntero alto] se ha movido (rellenado) al espacio anterior

Empezamos a mover el puntero inferior para señalar un elemento detrás del espacio

o

(2):

[El elemento señalado por el puntero bajo] se ha movido (llenado) al espacio detrás

Empezamos a mover el puntero alto para señalar el elemento anterior del espacio


El proceso completo de concreción:


(1):

No estoy seguro todavía:

El elemento señalado por el puntero alto] se ha movido (rellenado) al espacio anterior

Empezamos a mover el puntero inferior para señalar un elemento detrás del espacio


Al iniciar una comparación (nueva ronda) al principio (desde la segunda declaración if/else)

Si la situación que encontramos es: el elemento señalado por el puntero alto no es más pequeño que el centinela

(Lr[high].key < Lr[0].key) no está establecido, así que ejecute la sentencia else: high--;

Ejecute la segunda sentencia if/else:

Todo está bien aquí, y luego algo sale mal en el siguiente paso:

De acuerdo con nuestro proceso de operación manual, el siguiente paso del programa debería haber seguido ejecutando "high--";

Pero en el Proyecto 1, de acuerdo al flujo de operación del programa del Proyecto 1, el siguiente paso es:

  • Si el primer elemento apuntado por bajo es mayor que el centinela: Lr[alto] = Lr[bajo];alto--;

    Coloque el elemento puntero alto directamente en el espacio. En este caso, a menos que el penúltimo elemento sea un poco más pequeño que el centinela, también es una inserción incorrecta.


  • Si el primer elemento señalado por low es menor o igual que el centinela, low++;

    Mueva el puntero inferior directamente y no se encontrarán más espacios.


(2):

No estoy seguro todavía:

[El elemento señalado por el puntero bajo] se ha movido (llenado) al espacio detrás

Empezamos a mover el puntero alto para señalar el elemento anterior del espacio


Al iniciar una comparación (nueva ronda) al principio (desde la segunda declaración if/else)

Si la situación que encontramos es: el elemento apuntado por el puntero bajo no es más grande que el centinela
 
(Lr[0].key < Lr[low].key) no es verdadero, así que ejecute la sentencia else: low++;

Vuelva a ejecutar la primera instrucción if/else


Si el primer elemento apuntado por alto es más pequeño que el centinela: Lr[bajo] = Lr[alto];bajo++;

Coloque directamente el elemento de puntero bajo en el espacio. En este caso, a menos que el segundo elemento sea un poco más grande que el centinela, también es una inserción incorrecta.

Si el primer elemento señalado por alto es mayor o igual que el centinela, alto--;

Mueva el puntero alto directamente y no se encontrarán más espacios.


En el análisis final, el núcleo del problema del programa es la operación realizada por el programa:

No se confirma encontrar el siguiente elemento con un espacio en blanco antes de continuar con el siguiente paso (operación de cambio de puntero)

En cambio, siempre que se compare el siguiente elemento, se intercambie el elemento o se mueva el puntero de posición, se realizará el siguiente paso.

Modifique el resultado final de la siguiente manera:

#include<iostream>
using namespace std;

#define MAXSIZE 20  //记录最大个数
typedef int KeyType;  //关键字类型

typedef int InfoType;

//定义每个记录(数据元素)的结构
struct RecType
    //Record Type:每条记录的类型
{
    KeyType key;  //关键字
    InfoType otherinfo;  //其他数据项
};

struct SqList
    //顺序表(的)结构
{
    RecType r[MAXSIZE + 1];
    //类型为【记录类型】的数组
    //r[0]一般做哨兵或缓冲区
    int length;  //顺序表长度
};

int 遍历(SqList& L, int low, int high)
{
    L.r[0] = L.r[low];
    while (low < high)
    {
        //从后往前遍历,指向小于等于哨兵的元素:退出循环、插入空格
        while (low < high && L.r[high].key > L.r[0].key)         
            high--;
        L.r[low] = L.r[high];

        //继续,从前往后遍历,指向大于等于哨兵的元素:退出循环、插入空格
        while (low < high && L.r[0].key < L.r[low].key)
            low++;
        L.r[high] = L.r[low];
    }
    L.r[low] = L.r[high] = L.r[0];
    return low;
}

void QuickSort(SqList& L, int low, int high)
{
    int pivot = 遍历(L, low, high);
    QuickSort(L, low, pivot - 1);
    QuickSort(L, pivot + 1, high);
}

int main()
{
    SqList L;
    cin >> L.length;
    cin >> L.r->key;

    QuickSort(L, 1, L.length);
}

La diferencia con el programa que escribimos anteriormente es:

Solo cambiamos la operación del puntero después de estar seguros de encontrar un elemento más grande o más pequeño que el centinela y nos aseguramos de insertar el espacio

Sin embargo, el programa anterior realizará la operación de cambiar el puntero independientemente de si se encuentra o se intercambia.

De hecho, el resultado que queremos modificar es dejar que el programa determine que la operación de insertar espacios se realiza antes de continuar con el siguiente paso (siguiente ronda)


Por supuesto, todavía hay una diferencia entre esta modificación y la respuesta estándar, pero no mucha:

respuesta estándar:

int Partition(SqList& L, int low, int high)
{
    L.r[0] = L.r[low];
    KeyType pivotkey = L.r[low].key;
    while (low < high) 
    {
        while (low < high && L.r[high].key >= pivotkey)
            high--;  
        L.r[low] = L.r[high];

        while (low < high && L.r[low].key < pivotkey)
            low++;
        L.r[high] = L.r[low];
    }
    L.r[low] = L.r[0];
    return low;
}

void QuickSort(SqList& L, int low, int high) {
    if (low < high)
    {
        int pivotloc = Partition(L, low, high);  //将L一份为二
        QuickSort(L, low, pivotloc - 1);  //对低子表递归排序
        QuickSort(L, pivotloc + 1, high);  //对高子表递归排序
    }
}

int main()
{

}

La única diferencia es que la respuesta estándar ha configurado especialmente una clave dinámica variable para este nodo de comparación.

Siento que en realidad no hay nada a lo que aferrarse, y es inútil, no es tan simple y conveniente como lo que escribí.

Eso es todo, Cnmd, escribir este artículo y hacer esta cola rápida me ha sacudido durante al menos 5 días a la semana, estoy realmente sin palabras.

eso es todo

Supongo que te gusta

Origin blog.csdn.net/Zz_zzzzzzz__/article/details/130567024
Recomendado
Clasificación