Quicksort (no recursivo)

Quicksort no es recursivo:

La idea básica (ascendente por defecto): seleccione un número de la matriz como el número estándar, coloque todos los números menores que este número delante de él y coloque los números mayores que este número detrás de él. La posición es su posición en la matriz ordenada, por lo que no es necesario mover el número estándar. Continuamos realizando las operaciones anteriores en los números de los lados izquierdo y derecho, de modo que la posición de un número estándar en la matriz ordenada se pueda determinar cada vez. , hasta que todos los números estén en las posiciones correctas, momento en el cual la matriz es una matriz ordenada.

mejoramiento:

El medio de tres números: cuando tomamos el número estándar, cuanto más central es el número, menor es la complejidad temporal del algoritmo y cuanto más cerca de O(N*logN) mayor es la eficiencia. Cuanto más extremo es el número que tomamos , cuanto más cerca esté del valor máximo o mínimo. Cuanto mayor sea la complejidad del tiempo, más cerca de O(N^2), menor será la eficiencia. Por lo tanto, el número estándar obtenido mediante el método de los tres números está más centrado. El valor específico La operación es tomar tres números de tres posiciones al principio y al final de la matriz, y luego usar El número del medio entre estos tres números es el número estándar.

extensión:

Método Hoare : primero seleccione el número estándar, luego defina dos punteros (anterior (frente), posterior (trasero)), uno de adelante hacia atrás, uno de atrás hacia adelante, use prev para encontrar un número mayor que el número estándar, use trasero Encuentre un número más pequeño que el número estándar, y luego intercambie los dos números hasta que el anterior y el posterior vayan a la misma posición para salir del ciclo, y luego intercambie el número estándar con aquí.

Método de excavación: primero seleccione el número estándar, coloque el número escalar al final de la matriz y luego regístrelo en temperatura, luego defina anterior (frontal), posterior (posterior), anterior vaya primero para encontrar el número más grande que el número estándar y colóquelo directamente al final de la matriz, luego Rear continúa caminando para encontrar una posición más pequeña que el número estándar y colóquelo directamente en anterior, y continúe repitiendo la operación anterior hasta que anterior y posterior se unan para salir del bucle, y pon el número en temp aquí.

Método de puntero delantero y trasero: primero seleccione el número estándar, coloque el número estándar en la cabeza de la matriz y luego defina el puntero delantero y trasero anterior en la cabeza, cur = anterior + 1, los dos punteros retroceden juntos, cur encuentra un número más pequeño que el número estándar, y prev encuentra la proporción Si el número estándar es grande, se encuentra e intercambia. Cuando cur llega al final, se sale del ciclo. Porque la posición de prev es siempre el último dígito del número más pequeño que el número estándar, el número estándar y la posición anterior se intercambian, y el número estándar se puede colocar en el medio.

Pensamiento no recursivo: los tres métodos anteriores solo pueden realizar una operación en los datos. En otras palabras, ejecutar uno de los tres algoritmos anteriores solo puede determinar la posición de un número estándar. En este momento, es necesario Continuamos llame a este algoritmo para operar en los datos en ambos lados del número estándar hasta que todos los datos estén en orden. Es muy conveniente usar llamadas recursivas. Cada vez que los datos en los lados izquierdo y derecho del número estándar se usan como el Intervalo para hacer dos llamadas recursivas, pero estamos usando un método no recursivo aquí, por lo que podemos usar la pila para simular el proceso de llamadas recursivas, para usar un bucle para implementar una ordenación rápida, primero empuje las posiciones de inicio y fin de la matriz en la pila, y luego comience con la pila vacía como condición Realice el ciclo, saque dos elementos de la pila como un intervalo y realice una ordenación rápida, la función devolverá la posición de un valor estándar, y juzgue con el punto inicial y el punto final en el lado izquierdo y el punto inicial y el punto final en el lado derecho. El punto inicial es más pequeño que el punto final. En cada caso, empújelos a la pila respectivamente, y luego continúe bucle hasta que la pila esté vacía.

Gráfico:

 

Código:

#include<stdio.h>
#include<stdlib.h>
#define SIZE 100
 
void Swap(int* a,int* b){//对数组中的两个数据进行交换
  int temp=*b;
  *b=*a;
  *a=temp;
}
 
//取中间数
int MidNum(int* a,int b,int c,int d){
  int n_1=a[b],n_2=a[c],n_3=a[d];
  int temp[3]={n_1,n_2,n_3};
  if(temp[0]>temp[1]){
    Swap(&temp[0],&temp[1]);
  }
  if(temp[1]>temp[2]){
    Swap(&temp[1],&temp[2]);
  }
  if(temp[0]>temp[1]){
    Swap(&temp[0],&temp[1]);
  }
  if(temp[1]==a[b]){
    return b;
  }
  if(temp[1]==a[c]){
    return c;
  }
  return d;
}
 
//hoare
int PartSort1(int* a,int left,int right){//降序
  int i=left,j=right,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[right],&a[mid]);//将标准数放到末尾
  int temp=a[right];//记录标准数
  while(i<j){
    while(i<j && a[i]>=temp){//找比标准数小的
      i++;
    }
    while(i<j && a[j]<=temp){//找比标准数大的
      j--;
    }
    Swap(&a[i],&a[j]);//交换
  }
  Swap(&a[i],&a[right]);//将标准数放到中间
  return i;
}
 
//挖坑法
int PartSort2(int* a,int left,int right){
  int i=left,j=right,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[mid],&a[right]);//将标准数放到末尾
  int temp=a[right];//记录标准数
  while(i<j){
    while(i<j && a[i]<=temp){//找比标准数大的数
      i++;
    }
    if(i<j){//将其放到j的位置
      a[j]=a[i];
      j--;
    }
    while(i<j && a[j]>=temp){//找比标准数小的数
      j--;
    }
    if(i<j){//将其放到i的位置
      a[i]=a[j];
      i++;
    }
  }
  a[i]=temp;//将标准数的值放到中间
  return i;
}
 
//前后指针法
int PartSort3(int* a,int left,int right){
  int cur,prev,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[left],&a[mid]);//将标准数放到首部
  prev=left;//定义前后指针
  cur=prev+1;
  while(cur<=right){
    if(a[cur]<a[left] && ++prev!=cur){//cur找比标准数小的,prev找比标准数大的然后交换
      Swap(&a[cur],&a[prev]);
    }
    cur++;
  }
  Swap(&a[left],&a[prev]);//prev所在的位置永远在小于标准数的最后一位,将标准数与其交换放在中间
  return prev;
}
 
//非递归

typedef int DataType;
typedef struct Stack{//定义栈
  DataType a[SIZE];
  int size;
}Stack;

void InitStack(Stack* s){//初始化栈
  s->size=0;
}

void StackPush(Stack* s,DataType val){//入栈
  s->a[s->size++]=val;
}

void StackPop(Stack* s){//出栈
  s->size--;
}

DataType StackTop(Stack* s){//获取栈顶元素
  return s->a[s->size-1];
}

void QuickSortNoR(int* a,int left,int right){//非递归调用
  if(left>=right){//数组元素小于等于1直接退出
    return;
  }
  Stack s;//创建栈
  InitStack(&s);//初始化栈
//将数组的起点和终点入栈,因为栈是先入后出的特性,为了方便后续使用让right先入,left后入.
  StackPush(&s,right);
  StackPush(&s,left);
  while(0!=s.size){//以栈空为条件开始模仿递归调用进行循环调用.
    int i=StackTop(&s);//将数组中的两个元素取出,作为第一个区间开始调用快排.
    StackPop(&s);
    int j=StackTop(&s);
    StackPop(&s);
    int mid=PartSort3(a,i,j);//调用一次快排,并返回标准数所在的位置.
    if(mid>i+1){//判断标准数左侧是否还存在区间,存在就将其起点和终点入栈.
      StackPush(&s,mid-1);
      StackPush(&s,i);
    }
    if(mid<j-1){//判断标准数右侧是否还存在区间,存在就将其起点和终点入栈.
      StackPush(&s,j);
      StackPush(&s,mid+1);
    }
  }
}
 
void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}
 
int main(){测试
  int a[]={3,4,2,7,5,6,9,8,1};
  QuickSortNoR(a,0,sizeof(a)/sizeof(a[0])-1);
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_49312527/article/details/123464687
Recomendado
Clasificación