快速排序
-
基本思想
任取待排序元素序列中的某元素作为基准值(key),按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上;
快速排序将区间按照基准值划分为左右两半部分的常见方式有:
- hoare版本
- 挖坑法
- 前后指针版本
-
图片说明
注:
- 升序:左边找比key大的值,右边找比key小的值;
- 左边做key,右边先走;右边做key,左边先走;
-
代码实现
#include<stdio.h> #include<stdlib.h> void Swap(int* p1, int* p2) { int tmp = *p1; *p1 = *p2; *p2 = tmp; } int Hoare(int* a,int begin,int end)//hoare法(左右指针法) { int key = a[end]; int keynum = end;//key的下标 while (begin < end) { while (begin < end && a[begin] <= key)//找比key值大的 begin++; while (begin < end && a[end] >= key)//找比key值小的 end--; Swap(&a[begin], &a[end]); } Swap(&a[begin], &a[keynum]); return begin; } int DigPit(int *a, int begin, int end)//挖坑法 { int key = a[end]; while (begin < end) { while (begin < end && a[begin] <= key)//找比key值大的 begin++; a[end] = a[begin]; while (begin < end && a[end] >= key)//找比key值小的 end--; a[begin] = a[end]; } a[begin] = key; return begin; } int PrevCur(int* a, int begin, int end)//前后指针法 { int prev = begin - 1; int cur = begin; int key = a[end]; while (cur < end)//把比key值小的数全部往前移 { if (a[cur] < key) { prev++; Swap(&a[cur], &a[prev]); } cur++; } prev++; Swap(&a[end], &a[prev]); return prev; } void QuickSort(int* a,int begin,int end) { if (begin >= end) return; int keynum = Hoare(a, begin,end); //int keynum = DigPit(a, begin, end); //int keynum = PrevCur(a, begin, end); //[begin keynum-1] keynum [keynum+1 end] QuickSort(a, begin, keynum - 1);//key左边 QuickSort(a, keynum + 1, end);//key右边 } int main() { int a[] = { 9, 2, 3, 4, 8, 4, 1, 7, 5, 6 }; QuickSort(a, 0, sizeof(a) / sizeof(int)-1); for (int i = 0; i < sizeof(a) / sizeof(int); i++) { printf("%d ", a[i]); } system("pause"); return 0; }
-
特性总结
-
快排在有序的情况下会很慢;
-
快速排序在最坏的情况下退化为冒泡排序,需要比较O(N*2)次;
-
时间复杂度:O(N*logN)
-
空间复杂度:O(logN)
-
稳定性:不稳定
-
快排的非递归方法可使用栈实现;
快速排序防止最坏的情况发生方法:
- 随机选key(不靠谱)
- 三数取中法