今天我们要讲的是快速排序,非常的哇塞!
简单了解一下快排------

下面介绍快排的三个方法,未优化和优化后的快排
First----hoare版本
也就是说先确立的一个下标为key的值为对比值,普遍可以认为左边第一个值就key值,然后,从右边发出,寻找比key值小的数字,当R停下时,L才动,然后找到比key大的值,然后进行L、R的交换,最终他们一定会相遇,相遇的下标对应的值就将key赋值给他,然后再分而治之,
[left,key-1] key [key+1,right] 就是一样一个递归
数据结构一定要学会画图来思考问题,让问题更加地清晰明了!

完整代码:
- //hoare版本
- void QuickSort(int* arr, int begin, int end)
- {
- //进来判断一下
- if (begin >= end)
- {
- return;
- }
- int left = begin;
- int right = end;
- int key = left;
- while (left < right)
- {
- //先走右边
- while (left < right && arr[right] >= arr[key])
- {
- --right;
- }
- while (left < right && arr[left] <= arr[key])
- {
- ++left;
- }
- //交换
- Swap(&arr[left], &arr[right]);
- }
- //最后相遇了
- Swap(&arr[key], &arr[left]);
- key = left;//更新key的位置
- QuickSort(arr, begin, key - 1);
- QuickSort(arr, key + 1, end);
-
- }
- void PrintSort(int* arr, int len)
- {
- for (int i = 0; i < len; i++)
- {
- printf("%d ", arr[i]);
- }
- }
- int main()
- {
- int arr[] = { 3,1,2,4,9,5,6};
- int len = sizeof(arr) / sizeof(arr[0]);
- QuickSort(arr,0, len-1);
-
- PrintSort(arr, len);
- }
下面介绍另外一种方法,被大神们优化一下, 比较好理解!
2、挖坑法-------顾名思义就是有一个坑

完整代码:
//挖坑法
void QuickSort(int* arr, int begin, int end)
{
if (begin >= end)
{
return;
}
int left = begin;
int right = end;
int key = arr[left];
int piti =left;//坑位
while (left < right)//控制范围
{
while (left < right && arr[right] >= key)
{
--right;
}
arr[piti] = arr[right];
piti = right;
while (left < right && arr[left] <= key)
{
++left;
}
arr[piti] = arr[left];
piti = left;
}
//还有最后相遇的一个坑位
arr[piti] = key;
QuickSort(arr, begin, piti - 1);
QuickSort(arr, piti + 1, end);
}
void PrintSort(int* arr, int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = { 3,1,2,4,9,5,6};
int len = sizeof(arr) / sizeof(arr[0]);
QuickSort(arr,0, len-1);
PrintSort(arr, len);
}
第三种方法:前后指针版本

完整代码:
- //前后指针版本
- void QuickSort(int* arr, int begin, int end)
- {
- if (begin >= end)
- {
- return;
- }
- int prev = begin;
- int cur = begin + 1;
- int key = begin;
- while (cur <= end)
- {
- if (arr[cur] < arr[key] && ++prev != cur)
- {
- Swap(&arr[cur], &arr[prev]);
- }
- ++cur;
- }
-
- //最后只剩下一个prev
- Swap(&arr[prev], &arr[begin]);
- key = prev;
- QuickSort(arr, begin, key - 1);
- QuickSort(arr, key + 1, end);
- }
- void PrintSort(int* arr, int len)
- {
- for (int i = 0; i < len; i++)
- {
- printf("%d ", arr[i]);
- }
- }
- int main()
- {
- int arr[] = { 3,1,2,4,9,5,6};
- int len = sizeof(arr) / sizeof(arr[0]);
- QuickSort(arr,0, len-1);
-
- PrintSort(arr, len);
- }
相信你学会这三种快排的方法不算难事,但是那都是没进行过优化的,接下来让我们来优化一下吧!前面三种方法的时间复杂度都是O(N),在效率上并没有提升太多
优化方法—:三数取中(在前后指针版本上面改善)
影响效率的障碍就是key,要不每次key都是最小,要 不key每次都是最大,那么效率肯定就上不去,如果我们让key是区域内的middle 那么效率更上一层了,所以三数取中。
- //前后指针版本
- void QuickSort(int* arr, int begin, int end)
- {
- if (begin >= end)
- {
- return;
- }
- int prev = begin;
- int cur = begin + 1;
- int key = begin;
-
- //三数取中
- int mid = GetMidIndex(arr, begin, end);
- Swap(&arr[key], &arr[mid]);
- while (cur <= end)
- {
- if (arr[cur] < arr[key] && ++prev != cur)
- {
- Swap(&arr[cur], &arr[prev]);
- }
- ++cur;
- }
-
- //最后只剩下一个prev
- Swap(&arr[prev], &arr[begin]);
- key = prev;
- QuickSort(arr, begin, key - 1);
- QuickSort(arr, key + 1, end);
- }
优化方法二:递归到小的子区间时,可以考虑使用插入排序

因为在数据有序或者接近有序的时候,插入排序的效率非常可观,至于为什么不用希尔,堆,是因为在大数据下用他们比较快,但是接近有序的时间复杂度插入排序更胜一筹!
这些数据划分区域就知道最后接近有序的递归次数就占了一半,所以说非常的庞大。
区域优化代码:

这里的插入排序的arr如果不加begin的话,那么每次都是最前面的20个数进行排序,那么无意义,arr+begin就是不同区域内的begin----end
这个优化就非常的爽了!
这些快排都是运用了递归的方式,递归也是一定的劣势,所以我们也必须要掌握非递归的方式
非递归我们运用的是栈完成快排
栈的性质是先进后出,我们可以完美地运用这个性质!
思路:
这完全就像是树的工作方式,先完成左树的排序,然后再进行右树的排序,穷尽到最后一个区域,最后再销毁一下栈就可以实现非递归的快排了
更形象一点:当然用队列也是一样的,运用好队列的性质就行好,控制好

因为这是纯C所以要先手搓一个栈,到C++就不用这么麻烦了,
非递归完整代码:
- //栈
- typedef struct Stack
- {
- int* arr;
- int top;
- int capacity;
- }Stack;
-
- void InitStack(Stack* ps)
- {
- ps->arr = NULL;
- ps->top = ps->capacity = 0;
- }
-
- void StackPush(Stack* ps,int x)
- {
- //检测是否满了
- if (ps->top == ps->capacity)
- {
- int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
- int tmp = (int *)realloc(ps->arr,sizeof(int )*newcapacity);
- ps->arr = tmp;
- ps->capacity = newcapacity;
-
- }
- ps->arr[ps->top] = x;
- ps->top++;
-
- }
-
- void StackPop(Stack* ps)
- {
- ps->top--;
- }
-
- void DestoryStack(Stack* ps)
- {
- ps->arr = NULL;
- ps->top = ps->capacity = 0;
- }
-
- int StackTop(Stack* ps)
- {
- return ps->arr[ps->top-1];
- }
-
- bool StackEmpty(Stack* ps)
- {
- return ps->top==0;
- }
-
- //栈来实现非递归的快排
- void QuickSort(int* arr, int begin, int end)
- {
- Stack st;
- InitStack(&st);
- StackPush(&st, end);
- StackPush(&st, begin);
- while (!StackEmpty(&st))
- {
- int left = StackTop(&st);
- StackPop(&st);
- int right = StackTop(&st);
- StackPop(&st);
-
- int keyi = QuickSort2(arr, left, right);
- if (left < keyi - 1)
- {
- StackPush(&st, keyi - 1);
- StackPush(&st, left);
- }
- if (keyi + 1 < right)
- {
- StackPush(&st, right);
- StackPush(&st, keyi + 1);
- }
- }
- DestoryStack(&st);
- }
- void PrintSort(int* arr, int len)
- {
- for (int i = 0; i < len; i++)
- {
- printf("%d ", arr[i]);
- }
- }
- int main()
- {
- int arr[] = { 3,1,2,4,9,5,6};
- int len = sizeof(arr) / sizeof(arr[0]);
- QuickSort(arr,0,len-1);
-
- PrintSort(arr, len);
- }
伙伴们!快来试一下吧!!
如有错误,请指出!