交换排序(2)--快速排序3种实现方案及其优化
来源:互联网 发布:ubuntu 笔记本 编辑:程序博客网 时间:2024/06/05 19:18
快速排序
快排的整体思想是找出一个key值,比key的值小的都在它的左边,比key大的值都在它的右边。这样就划分了左右两个区域,分别找左右两个区域的key值继续划分左右区间。
找中间值的位置有三种方法
(1)左右指针法
思想:在序列的左右各定义begin,和end这两个指针。begin++往右走,当遇到比key大的值停下。end--往左走,遇
到比key小的值后停下。此时交换begin和end下标所代表的值。(使得比key大的数在右边,比key小的数在左边)。当
begin和end相遇时,把这个值和key值交换。此时序列中比key大的数都在key右边,比key小的数都在key左边(分成了
左右两个区间)。把key的下标返回,继续找区间的key。
int PartSort1(int* a, int left, int right)//6---1左右指针法{int mid = GetMidIndex(a, left, right);swap(a[mid], a[right]); //优化1 三数取中法,避免KEY值是最大值或最小值。int begin = left;int end = right;int key = a[right];while (begin < end){while (begin < end&&a[begin] <= key){++begin;}while (begin < end&&a[end] >= key){--end;}if (begin < end){swap(a[begin], a[end]);}}swap(a[begin], a[right]);return begin;}
(2)挖坑法
思想:1 选择最右的值为key值,并把key值得位置当做第一个坑,找到合适的数来填坑。依旧定义begin和end两个最左
最右的指针。2 让begin++,先往左走,当遇到比key大的数停下,此时拿begin位置上的数去填第一个坑,此时坑的位
置在begin的位置上。3 再让end--,往右走,当遇到比key小的数停下,拿end位置上的数去填坑(坑此时在begin的置)。
当填完后,坑现在在end的位置上。4 重复上述动作,直到end和begin相遇,此时坑在begin和end位置上,拿key值来填
这个坑。
int PartSort2(int* a, int left, int right)//6--2 挖坑法,先把key的值得位置当成坑{int mid = GetMidIndex(a, left, right);swap(a[mid], a[right]); //优化三数取中法int begin = left; //定义beginint end = right; //定义endint key = a[right]; //定义keywhile (begin < end) //循环 当begin<end时继续{while (begin < end&&a[begin] <= key) //a[begin]<key,begin继续往左走{++begin;}a[end] = a[begin]; //填坑-->赋值while (begin < end&&a[end] >= key){--end;}a[begin] = a[end];}a[begin] = a[end] = key; //循环出来,begin=end ,把key值给到这个位置上填坑return begin; //任意返回begin或者end}
(3)前后指针法:
思想:1定义一个下标cur,刚开始赋值为序列的最左。再定义一个prev,赋值为cur-1,意思是cur的前面一个数的下标。2 用cur下标代表的数与key比较,若比key值大,则cur++往右走。若比key值小,先让prev++往右走,在比较prev和cur是不是在同一个位置上,若不在同一个位置,则,交换prev和cur所代表的数值。cur继续往前走。
int PartSort3(int* a, int left, int right)// 6---3前后指针法{int mid = GetMidIndex(a, left, right);swap(a[mid], a[right]); int cur = left;int prev =cur-1;int key = a[right];while (cur < right){if (a[cur] < key&&++prev != cur){swap(a[prev], a[cur]);}++cur;}++prev;swap(a[prev], a[right]);return prev;}
2种优化方案
1 三数取中法
//优化快排 三数取中。避免a[div]是最大值或最小值int GetMidIndex(int* a, int left, int right){int mid = left + (right - left) / 2;if (a[left] > a[mid]){if (a[mid] > a[right])return mid;else if (a[right] > a[left])return left;elsereturn right;}else//a[left]<a[mid]{if (a[mid] < a[right])return mid;else if (a[right] < a[left])return left;elsereturn right;}}
思想:在区间范围较小时,不选择快排算法。而选择插入算法。这样是算法的优化。
void QuickSort(int*a, int left, int right) //6 快速排序{if (left < right){int div = PartSort1(a, left, right);if (right - left < 5) //小区间优化{InsertSort(a,right-left+1);}else //若左右区间大的话直接还是用快排方法。{QuickSort(a, left, div - 1);//左QuickSort(a, div + 1, right);//右}}}
快排非递归:借助栈结构
void QuickSortNR(int *arr, int begin, int end){ assert(arr); stack<int> s; s.push(begin); s.push(end); while (!s.empty()) { int left = s.top(); s.pop(); int right = s.top(); s.pop; int div = PartSort3(arr, left, right); if (div - 1 > left) { s.push(div - 1); s.push(left); } if (div + 1 < right) { s.push(right); s.push(div + 1); } }}
总结:
快速排序对于小规模的数据集性能不是很好。没有插入性能高。快速排序算法使用了分治技术,最终来说大的数据集都要分为小的数据集来进行处理。
当数据集较小时,不必继续递归调用快速排序算法,使用插入排序代替快速排序。(小区间优化)
快速排序是时间复杂度是O(N*LogN).
最好情况:O(N*LogN).
最坏情况:O(N^2) :当序列中的数值都相等时,快排是最坏的情况。
空间复杂度:O(lgN)
快排是一种不稳定的排序算法。
- 交换排序(2)--快速排序3种实现方案及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 数据结构-快速排序的三种实现方式及其优化
- 交换排序实现(冒泡排序,快速排序)
- 排序算法-快速排序(三种实现方案)
- 选择排序及其优化方案
- 插入排序及其优化方案
- 希尔排序及其优化方案
- 5并行数据加载
- 二级指针输入模型(三种内存模型)
- POJ 1655 Balancing Act
- eclipse中使用git
- Java操作Excel基本
- 交换排序(2)--快速排序3种实现方案及其优化
- C++引用/枚举/typedef/头文件/预编译器/自定义头文件
- stl-set
- Scala Extractor Objects
- [数论] LOJ #510. 「LibreOJ NOI Round #1」北校门外的回忆
- 计算机图形学 学习笔记(五):多边形裁剪(Suther land-Hodgeman),文字裁剪
- java的文件xml读取,4种方式的不同
- centos安装THEFUCK
- 牛客《剑指Offer》 -- 斐波那契数列