Tipo rápido de algoritmo de clasificación (tres recursivos y no recursivos)

Tabla de contenido

1. Implementación recursiva de clasificación rápida

1. Clasificación rápida (método Hoare), también conocido como método de puntero izquierdo y derecho

2. Clasificación rápida (método de excavación de pozos)

3. Clasificación rápida (método de puntero de ida y vuelta)

En segundo lugar, la implementación no recursiva de clasificación rápida

3. Resumen de las características de clasificación rápida


1. Implementación recursiva de clasificación rápida

1. Clasificación rápida (método Hoare), también conocido como método de puntero izquierdo y derecho

Su idea :

Primero seleccione un número como clave (objeto de referencia ). Generalmente, elija el extremo izquierdo como clave y luego comience desde el extremo derecho (si elige el extremo derecho como clave, comience primero desde la izquierda, de lo contrario se intercambiará fuera de Deténgase cuando el número sea menor que el valor señalado por la tecla, y luego camine desde la izquierda, deténgase cuando encuentre un número mayor que el valor señalado por la tecla, y finalmente intercambie los valores correspondientes al punteros izquierdo y derecho (subíndices), e iterar secuencialmente hasta que los punteros izquierdo y derecho se encuentren. Baje y luego intercambie el valor señalado por la clave con el valor señalado por los punteros izquierdo y derecho en este momento, y el la clasificación se completa En este momento, los valores de la izquierda son más pequeños que los valores señalados por la tecla, y los valores de la derecha son más grandes que los valores señalados por la tecla.

Finalmente, comenzando desde la posición donde los punteros izquierdo y derecho son iguales, la secuencia se divide en subsecuencias izquierda y derecha. En este momento, el lado izquierdo es menor que el valor señalado por la tecla, y el lado derecho es mayor que el valor apuntado por la tecla Luego deje que las subsecuencias izquierda y derecha repitan el proceso anterior.

Nota: clave significa subíndice

void Swap(int* p1, int* p2)
{
  int tmp = *p1;
  *p1 = *p2;
  *p2 = tmp;
}

void Quicksort(int* a,int left ,int right)//左右指针法
{
   if (left >= right)return;
    int l = left, r = right;
	int key = left;
  while (l < r)
  {
	while (l < r&&a[r]>=a[key])//注意这里需要相等,如果不相等
	{                            //左右指针同时遇到等于key的数将会发生死循环
		r--;
	}

	while (l < r && a[l] <= a[key])//这里也一样
	{
		l++;
	}

	Swap(&a[l], &a[r]);
  }

   Swap(&a[l], &a[key]);
   Quicksort(a,  left,  l-1);
   Quicksort( a,  r+1, right);
	
}

2. Clasificación rápida (método de excavación de pozos)

Idea: como sugiere el nombre, primero seleccione un número como valor de referencia (guarde este número con una variable tmp), y luego la posición correspondiente a este número quedará vacante (posición pit), generalmente elija el número más a la izquierda como valor de referencia , Comience desde la derecha primero (si elige el número más a la derecha, comience desde la izquierda primero), deténgase cuando encuentre un valor más pequeño que tmp, complete el valor en la posición vacante y luego camine desde la izquierda. Deténgase cuando encuentre un valor valor mayor que tmp, complete el valor en la posición vacía e itere a su vez.

Deténgase hasta que se encuentren y ponga tmp donde se encuentren.

Finalmente, divida toda la secuencia en subsecuencias izquierda y derecha comenzando desde la posición tmp. En este momento, los valores de la izquierda son menores que tmp, y los valores de la derecha son mayores que tmp, y luego repita el proceso anterior para las subsecuencias izquierda y derecha.

 

 

void Quicksort(int* a, int left, int right)//挖坑法
{
  if (left >= right)return;
  int l = left, r = right;
  int tmp = a[left];

 while (l < r)
 {
	while (l < r && tmp <= a[r])
	{
		r--;
	}

	if(l<r)
	a[l++] = a[r];

	while (l < r && tmp >= a[l])
	{
		l++;
	}

	if(l<r)
	a[r--] = a[l];
}
	a[l] = tmp;
	Qs2(a, left, l-1 );
	Qs2(a, l+1 , right);
}

3. Clasificación rápida (método de puntero de ida y vuelta)

Idea: elija un número como valor de referencia (use la tecla para representar el subíndice de este número), generalmente elija el número más a la izquierda como valor de referencia, luego deje que un puntero pre (subíndice) sea igual a la tecla y deje que otro puntero cur ( subíndice) Igual a key+1, luego deje que el puntero cur retroceda, si encuentra un número más pequeño que el valor señalado por key, luego intercámbielo con el número correspondiente a pre+1, itere a su vez hasta que el puntero cur sea mayor que el límite más a la derecha, y luego salga del ciclo, intercambie el valor al que apunta key con el valor al que apunta pre en este momento, y luego asigne el valor de pre a key.

Finalmente, toda la secuencia se divide en subsecuencias izquierda y derecha a partir de la posición clave. En este momento, el lado izquierdo es más pequeño que el valor señalado por la clave, y el lado derecho es mayor que el valor señalado por la clave. Luego deje que las subsecuencias izquierda y derecha repitan el proceso anterior.

 

void Swap(int* p1, int* p2)
{
  int tmp = *p1;
  *p1 = *p2;
  *p2 = tmp;
}

void  Quicksort(int* a, int left, int right)//前后指针法
{
  if (left >= right)return ;

   int key = left;
   int cur = key+1, pre = key ;

   while (cur <= right)
   { 
   //pre+1等于cur时就不交换,因为没必要
      if (a[cur] <= a[key] && ++pre != cur)
      {
		 Swap(&a[cur], &a[pre]);
      }
		cur++;
   }

	Swap(&a[key], &a[pre]);
	key = pre;
	Quicksort(a, left, key-1);
	Quicksort(a, key+1, right);
}

En segundo lugar, la implementación no recursiva de clasificación rápida

Idea: La ordenación rápida es como el recorrido en orden previo de un árbol binario.Primero ordena la secuencia completa para que los números de la izquierda sean más pequeños que los números señalados por la tecla.

El lado derecho es mayor que el número señalado por la clave, y luego divida la secuencia completa en subsecuencias izquierda y derecha desde la posición clave, y luego realice la clasificación anterior en las subsecuencias izquierda y derecha a su vez. Es fácil de lograr con el pensamiento recursivo, pero cómo lograrlo con el no recursivo.

De acuerdo con la idea de recursividad, se puede imaginar que la subsecuencia izquierda se ordena primero y la subsecuencia derecha se ordena al final. Luego, en este momento, la implementación no recursiva se puede completar con la ayuda de la pila en la estructura de datos.

Primero coloque el subíndice más a la derecha en la pila, luego coloque el subíndice izquierdo en la pila, tome dos elementos por turno, ordene los intervalos correspondientes a estos dos elementos y, después de ordenar, divida el intervalo en subintervalos izquierdo y derecho. Luego, primero ingrese el dos subíndices del intervalo de la derecha, y luego ingrese los dos subíndices del intervalo de la izquierda (porque el intervalo de la izquierda debe organizarse primero) e iterar a su vez hasta que los elementos en la pila estén vacíos y el arreglo esté completo.

void Swap(int* p1, int* p2)
{
  int tmp = *p1;
  *p1 = *p2;
  *p2 = tmp;
}

int  Quicksort(int* a, int left, int right)//前后指针法
{
  if (left >= right)return ;

  int cur = left+1, pre = left ;
  int key = left;

   while (cur <= right)
   {  
        //pre+1等于cur时就不交换,因为没必要
      if (a[cur] <= a[key] && ++pre != cur)
      {
        Swap(&a[cur], &a[pre]);
      }
		cur++;
	}
	  Swap(&a[key], &a[pre]);
	  key = pre;
	  return key;
}

void QsortNonR(int* a, int left, int right)
{
	ST st;
	StackInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);

	while (!STEmpty(&st))
	{
		int L = StackTOP(&st);
		StackPop(&st);
		int r = StackTOP(&st);
		StackPop(&st);

		int mid=Quicksort(a, L, r);

		if (mid + 1 < r)
		{
			StackPush(&st, r);
			StackPush(&st, mid + 1);
		}
		if (L < mid - 1)
		{
			StackPush(&st, mid);
			StackPush(&st, L);
		}
	}

}

3. Resumen de las características de clasificación rápida

 Suponiendo que hay n números en la secuencia, como se puede ver en la figura anterior, cada número debe recorrerse aproximadamente logN veces, por lo que la escala de tiempo es N*logN y se debe establecer un marco de pila para cada recursión. se puede ver en la figura anterior, la profundidad de recursión máxima es logN, por lo que la complejidad del espacio es logN

1. Complejidad del tiempo: O(N*logN)

2. Complejidad del espacio: O(logN)

3. Estabilidad: Inestable

4. Los escenarios generales de rendimiento y aplicación integrales de ordenación rápida son relativamente buenos, por lo que se atreve a llamarse ordenación rápida

Supongo que te gusta

Origin blog.csdn.net/m0_72532428/article/details/130150979
Recomendado
Clasificación