赞
踩
(1)思想
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
(1)画图理解
取最左边key为基准值,用right指针找比key值小的元素,用left指针找比key位置大的元素,将两位置值进行交换,最后,将key值放在二者相遇位置上,就可保证key左边都是比key小的值,右边都是比key大的值,然后进行递归即可实现,从相遇点分割成两部分,在分别对左右两部分重复上述排序。
(2) 代码思路
//-----------------------快排-------------------/ int HoareSort(int* a, int begain, int end) { int key = begain; int left = begain, right = end; while (left < right) { //右边找比key小的值 while (left < right && a[right] >= a[key]) right--; //左边找比key大的值 while (left < right && a[left] <= a[key]) left++; swap(&a[right], &a[left]); } int meeti = left; swap(&a[meeti], &a[key]); return meeti; } void QuickSort(int* a, int begain, int end) { //递归返回条件如果该区间只有一个值或没有值则返回 if (begain >= end) return; int meeti = HoareSort(a, begain, end); QuickSort(a, begain, meeti - 1); QuickSort(a, meeti + 1, end); }
(1)画图理解
思路:取最左边或最右边值做key,右边形成一个坑,定义两个指针left、right指向头和尾。右边找小值放到左边坑中右边形成新坑,左边找大值放到右边左边形成新坑,将key放到相遇位置。这时key左边值均小于key,右边值均大于key。
(2) 代码思路
//挖坑法 int DigHoleSort(int* a, int begain, int end) { int key = a[begain]; int left = begain, right = end; while (left < right) { //右边找小值 while (left < right && a[right] >= key) right--; //放到左边坑位中,右边形成新的坑 a[left] = a[right]; //左边找大值 while (left < right && a[left] <= key) left++; //放到右边坑位中,左边形成新的坑 a[right] = a[left]; } int meeti = left; a[meeti] = key; return left; } void QuickSort(int* a, int begain, int end) { if (begain >= end) return; //int meeti = HoareSort(a, begain, end); int meeti = DigHoleSort(a, begain, end); QuickSort(a, begain, meeti - 1); QuickSort(a, meeti + 1, end); }
(1)画图理解
定义两指针一前一后,cur指针找比key小的值,和prev指针前一个值进行交换,直至结束。将prev位置值与key位置值进行交换,此时key位置值,左边比key位置值小,右边比key位置值大,在进行分治就可以了。
(2) 代码思路
int PBIndexSort(int* a, int begain, int end) { int key = begain; //定义两个指针,一前一后 int prev = begain, cur = begain + 1; while (cur <= end) { //如果cur位置值比key小则与perv前一个值进行交换 if (a[cur] < a[key] && ++prev != cur) { swap( &a[cur], &a[prev] ); } cur++; } //将key放在prev位置 swap(&a[prev], &a[begain]); return prev; } void QuickSort(int* a, int begain, int end) { if (begain >= end) return; //int meeti = HoareSort(a, begain, end); //int meeti = DigHoleSort(a, begain, end); int meeti = PBIndexSort(a, begain, end); QuickSort(a, begain, meeti - 1); QuickSort(a, meeti + 1, end); }
总结
三种方法最终目的都是为了让,key放到它应该排序的位置同时,key左边的值都比key小,key右边的值都比key大,然后进行分治就可以了。
(1)三数取中法取key
理想情况下我们每回选的key位置值都近似为数组中位数,这样每回递归都为二分。但当数据出现极端情况时,会使我们的快速排序效率大打折扣例如
优化代码
以hoare法为例
//三数取中法 int GetMidIndex(int* a, int left, int right) { int mid = (left + right) >> 1; if (a[mid] > a[left]) { if (a[mid] < a[right]) return mid; else if (a[left] < a[right]) return right; else return left; } else { if (a[mid] > a[right]) return mid; else if (a[left] < a[right]) return left; else return right; } } //hoare法(左右指针法) int HoareSort(int* a, int begain, int end) { int mid = GetMidIndex(a, begain, end); swap(&a[mid], &a[begain]); //这里我们仍然取key为最左边的数,只不过最左边的值变了 int key = begain; int left = begain, right = end; while (left < right) { //右边找比key小的值 while (left < right && a[right] >= a[key]) right--; //左边找比key大的值 while (left < right && a[left] <= a[key]) left++; swap(&a[right], &a[left]); } int meeti = left; swap(&a[meeti], &a[key]); return meeti; }
(2)小区间优化法
小区间优化法实际上就是减少递归的深度,以此来提升效率代码如下:
void QuickSort(int* a, int begain, int end) { if (begain >= end) return; //小区间优化法 当数据量比较大的时候可以通过调整参数(20),来减小递归次数,提高性能 if ((end - begain) > 20) { int meeti = HoareSort(a, begain, end); QuickSort(a, begain, meeti - 1); QuickSort(a, meeti + 1, end); } else { //数量比较少的时候用直接插入来排序 InsertSort(a + begain, end - begain + 1); } }
利用栈来存储区间下标,代码如下:要注意先数组头,后入数组尾。出栈时栈顶的数据为数组尾,在出才为头位置下标。代码如下:
void QuickSortNonR(int* a, int begain, int end) { Stack st; StackInit(&st); //入栈 StackPush(&st, begain); StackPush(&st, end); while (!StackEmpty(&st)) { //出栈 int right = StackTop(&st); StackPop(&st); int left = StackTop(&st); StackPop(&st); //单趟排序 int mid = HoareSort(a, left, right); if (left < mid - 1) { StackPush(&st, left); StackPush(&st, mid - 1); } if (mid + 1 < right) { StackPush(&st, mid + 1); StackPush(&st, right); } } StackDestory(&st); }
1、快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2、时间复杂度:O(N*logN)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。