快速排序及其优化
来源:互联网 发布:热阻流软件 编辑:程序博客网 时间:2024/05/21 12:49
快速排序的实现方式很多,看了一篇博客之后觉得他的实现方式最简洁。算法思路主要为:
1、先重排,选取一个基准值(可以每次选左边的,也可以随机选一个),使左边的元素都小于这个基准值,右边的元素都大于这个基准值。
2、递归求解。
详细一点的说来第一步的方法就是:
以6,10,22,15,3,4,8,12这一组数A为例。
第一步:选取最左端的6作为基准值comp=6,m=0,然后依次与A[1],A[2]。。。比较(i++),遇到A[4]比comp小,交换A[1](基准值的右边一个数)与A[4]的位置(++m),然后继续比较遇到A[5]比comp小,交换A[2]与A[5]的位置继续(++m),知道循环完数组A,得到6,3,4,10,22,15,8,12,退出循环后,最后将6与4做个交换(A[2]显然是分隔点),swap(A,l,m)即完成了一次重排:3,4,6,10,22,15,8,12比6小的均在左边,比6大的均在右边。
第二步:对左右部分继续递归求解即可。
总结一下:选取好基准点之后先不要动基准点的位置,就当个柱子在那,最后排好了其他数之后再拆了柱子将分界点处的数与其进行交换,否则基准值进行交换的话被换到哪里了都不知道,又要有个变量随时记录位置,我将这个方法称为立柱排序。
代码如下:
void swap(int* a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp;}void fast_sort(int *A,int l,int r){ if(l>=r) return;//当划分到元素个数为0或者1个时直接退出递归 int m=l; int comp=A[m]; for(int i=l+1;i<=r;i++) { if(A[i]<=comp)//这里的等号要加,当数组中重复的元素比较多时,等号可以提高算法的速度,虽然多了一次交换 swap(A,++m,i); } swap(A,m,l);//将基准值(左端点与分隔处交换) fast_sort(A,l,m-1); fast_sort(A,m+1,r);}
还有一种就是从一篇博客看来的挖坑排序,原理都是一样的,只是交换的方式不同,比前面的立柱排序执行的交换次数要少。还是以6,10,22,15,3,4,8,12为例来讲。
第一步:和前面一样,先选取一个基准值(挖坑),comp=A[0],然后从后向前找到比基准值小的数4(挖的新坑A[5]),填到A[0]的坑中,既A[m++]=A[n],然后从前向后找比基准值大的数,找到了10,填到刚刚坑A[5]中,现在又有个新坑A[1]。
第二步:重复第一步的操作,先从后向前找,在从前向后找,依次挖坑补坑,最后在m==n的时候停止,将comp(基准值)补到最后一个坑中
第三步:递归左右部分即可。
这里说明一下为什么要先从后向前呢?如果不这样的话就要有个中间变量来暂存进行交换(就和立柱排序一毛一样了),而先从后先前就可以直接将A[m]的坑填上,减少了赋值的操作。
代码如下:
void fast_sort(int *A,int l,int r){ if(l>=r)return; int m=l,n=r; int comp=A[m]; while(m<n) { //注意m<n的条件要时刻满足,否则在后面m和n继续递归时会越界 while(m<n&&comp<A[n])n--; if(m<n)A[m++]=A[n];//先从后向前找比基准值小的数放到左边去,即跳过比基准值大的数 while(m<n&&comp>=A[m])m++; if(m<n)A[n--]=A[m];//再从前向后找比基准值大的数放到右边去 } A[m]=comp; fast_sort(A,l,m-1); fast_sort(A,m+1,r);}
下面讲讲快速排序的优化,首先是基准点的选择上面,因为在不同情况下快排的性能可能会波动到O(n^2),所以可以随机选择基准点使其更接近平均值O(n*log2n),只需要每次随机选择的基准点与最左端的点做一次交换即可,完整代码如下
#include <string>#include <iostream>#include <ctime>#include <cstdlib>using namespace std;#define Maxn 100int T[Maxn] = { 3, 2, 1, 4, 10, 2, 3, 55, 22, 99, 45, 24, 35 };void swap(int* a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp;}double random(double start, double end){ return start + (end - start)*rand() / (RAND_MAX + 1.0);}void fast_sort(int *A,int l,int r){ if (l >= r)return; int m = l, n = r; int comp_pos = int(random(l, r + 1)); swap(A, m, comp_pos); int comp = A[m]; while (m<n) { while (comp<A[n]) n--; if (m<n) A[m++] = A[n];//先从后向前找比基准值小的数放到左边去 while (m<n&&comp >= A[m]) m++; if (m<n) A[n--] = A[m];//再从前向后找比基准值大的数放到右边去 } A[m] = comp; fast_sort(A, l, m - 1); fast_sort(A, m + 1, r);}int main(){ srand(unsigned(time(0))); fast_sort(T, 0, 10); return 0;}
进一步优化:
插入排序的时间复杂度是O(N^2),但是在已经排序好的数组上面,插入排序的最佳情况是O(n),插入排序在小数组的排序上是非常高效的,这给我们一个提示,在快速排序递归的子序列,如果序列规模足够小,可以使用插入排序替代快速排序,因此可以在快排之前判断数组大小,如果小于一个阀值就使用插入排序。所以可以在快排中引入插入排序
代码如下
void fast_sort(int *A,int l,int r){ if (l >= r)return; // 在数组大小小于7的情况下使用快速排序 if (r - l + 1 < 7) { for (int i = l; i <= r; i++) { for (int j = i+1; j > l && A[j - 1] > A[j]; j--) { swap(A, j, j - 1); } } return; } int m = l, n = r; int comp_pos = int(random(l, r + 1)); swap(A, m, comp_pos); int comp = A[m]; while (m<n) { while (comp<A[n]) n--; if (m<n) A[m++] = A[n];//先从后向前找比基准值小的数放到左边去 while (m<n&&comp >= A[m]) m++; if (m<n) A[n--] = A[m];//再从前向后找比基准值大的数放到右边去 } A[m] = comp; fast_sort(A, l, m - 1); fast_sort(A, m + 1, r);}
第一篇:
http://blog.csdn.net/morewindows/article/details/6684558.
第二篇:
http://www.blogjava.net/killme2008/archive/2010/09/08/quicksort_optimized.html。
到此说完了快速排序的内容,基本也能做到默写出算法的过程,我比较喜欢第一种立柱排序,因为第二种挖坑排序的条件m < n容易掉,且记忆起来没第一种容易。这里感谢两篇博客的作者,我只是理解后在这里总结了下我消化的内容。
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序及其优化
- 快速排序算法及其优化
- 快速排序算法及其优化
- 快速排序算法及其优化方法
- 排序(6)——快速排序及其优化
- 快速排序的优化及其与qsort的比较
- 《大话数据结构》读书笔记之快速排序源码及其优化
- 《算法导论》实验一:快速排序算法及其优化
- “Beginning Python”(三)“Template System”
- IE和chrome中,windows.location.href的不同跳转路径的解决方式
- win32 API创建菜单资源
- Linux系统配置
- 【数学基础】概率统计
- 快速排序及其优化
- vue+webpack环境搭建
- EventBus之进阶使用详解
- 安装nginx时,常常会因为缺少依赖组件
- Xshell连接虚拟机的Linux
- MySQL NDB集群安装配置(mysql cluster 9.4.13 installation)
- 对沉余字段的理解
- [C++ 从入门到放弃-08]C++STL之stack堆栈容器
- 李开复给程序员的七个建议