快速排序
- 快速排序也是分治的,但不同于分治的一点是,它有分隔的概念,把一个序列按照p分为两份,左边的小于等于p,右边的大于等于p,再对两边的序列重复这个过程,直到序列只有一个元素为止。
- 快速排序的最坏运行时间是O(n^2),证明如下:

- 快速排序的平均运行时间能达到O(nlg(n)),比较排序不能突破这个极限,可以把比较排序算法理解为决策树模型,决策树是一种满二叉树,注意这里的二叉树是国际定义的满二叉树,也就是说,所有的节点,要么是叶子节点,要么度为2,不存在度为1的节点:

以上就是一棵满二叉树,表示了对3,2,1进行排序的过程。可以看到,对于排列而言,n个元素对应n!个排列,也就对应树的n!个叶子节点,这里的n指的是待排序的元素的个数。最坏情况下的排序也就是最终到达高度最大的叶子节点,比较次数和树的高度相同。下面要证明的是,一棵对应n个元素组成的比较排序的决策树,它的高度的渐近下确界为nlg(n),也就是证明,高度h=Θ(nlg(n)):
- 快速排序有一个演化,就是内省式快速排序,它能够控制递归次数以及序列划分的质量,当划分的恨不均衡,算法时间复杂度向O(n^2)恶化时,能自动转换为堆排序。这个算法会在最后和三点中值快速排序合并在一起给出。
- 下面是快速排序的子程序,partition:
int partition(int* arr, int first, int last) { const int pivot = arr[last - 1]; int i = first - 1; for(int j = first; j < last - 1; ++j) { if(arr[j] <= pivot) std::swap(arr[++i], arr[j]); } std::swap(arr[++i], arr[last - 1]); return i; } - 下面是快速排序的主函数:
void Quicksort(int *arr, int first, int last) { if(first < last) { int r = partition(arr, first, last); Quicksort(arr, first, r); Quicksort(arr, r + 1, last); } }需要注意的是,partition的方法不只一种。最常用的是三点中值法,结合上面所说的对递归层次的限制,有下面这个内省式快速排序算法:
const int cThreshold = 32; const int cDeepthLmt = 10; //deepth limit.deepth limit. <span>2*lg(n) in SGI-STL int __xpartition(int *arr, int first, int last, int val) { //the same as std::partition. for(; ; ++first) { for(; first != last && arr[first] <= val; ++first) ; if(first == last) break; for(; first != (--last) && arr[last] > val;) ; if(first == last) break; std::swap(arr[first], arr[last]); } return first; } int __median3(int x1, int x2, int x3) { //median of 3 numbers. if(x1 > x2) std::swap(x1, x2); if(x1 > x3) std::swap(x1, x3); return std::min(x2, x3); } int __mean(int *arr, int first, int last) { //median 3 partition. int p = __median3(arr[first], arr[(last + first - 1) / 2], arr[last - 1]); return __xpartition(arr, first, last, p); } void __introsort_loop(int* arr, int first, int last, int m) { //main loop. while(last - first > cThreshold) { if((m--) == 0) { make_heap(arr + first, arr + last); sort_heap(arr + first, arr + last); //or std::partial_sort. return; } int povit = __mean(arr, first, last); //loop on the first half. __introsort_loop(arr, first, povit, m); //loop on the second half. first = povit + 1; //IntroSortLoop(arr, povit + 1, last); } // insertion_sort here, or in Introsort(). } void __insertion_sort(int*arr, int first, int last) { for(size_t i = 1; i != last; ++i) { int key = arr[i]; int j = (int)(i - 1); for(; j >= 0 && key < arr[j]; --j) arr[j + 1] = arr[j]; arr[j + 1] = key; } } void Introsort(int *arr, int first, int last) { __introsort_loop(arr, first, last, cDeepthLmt); __insertion_sort(arr, first, last); }
浙公网安备 33010602011771号