快速排序
来源:互联网 发布:excel2007数据库 编辑:程序博客网 时间:2024/06/15 14:26
快速排序的三个步骤:
1、分解:将数组A[l...r]划分成两个(可能空)子数组A[l...p-1]和A[p+1...r],使得A[l...p-1]中的每个元素都小于等于A(p),而且,小于等于A[p+1...r]中的元素。下标p也在这个划分过程中计算。
2、解决:通过递归调用快速排序,对数组A[l...p-1]和A[p+1...r]排序。
3、合并:因为两个子数组时就地排序,将它们的合并并不需要操作,整个数组A[l..r]已经排序。
1.快速排序的基础实现:
QUICKSORT(A, l, r)
if l < r
then q = PARTION(A, l, r)
QUICKSORT(A, l, p-1)
QUICKSORT(A, p+1, r)
两路PARTION算法主要思想:
move from left to find an element that is not less
move from right to find an element that is not greater
stop if pointers have crossed
exchange
实现代码:
- int partition(double* a, int left, int right)
- {
- double x = a[right];
- int i = left-1, j = right;
- for (;;)
- {
- while(a[++i] < x) { }
- while(a[--j] > x) { if(j==left) break;}
- if(i < j)
- swap(a[i], a[j]);
- else break;
- }
- swap(a[i],a[right]);
- return i;
- }
- void quickSort1(double* a, int left, int right)
- {
- if (left<right)
- {
- int p = partition(a, left, right);
- quickSort1(a, left, p-1);
- quickSort1(a, p+1, right);
- }
- }
2.非递归算法:其实就是手动利用栈来存储每次分块快排的起始点,栈非空时循环获取中轴入栈。
实现代码:
- void quickSort2(double* a, int left, int right)
- {
- stack<int> t;
- if(left<right)
- {
- int p = partition(a, left, right);
- if (p-1>left)
- {
- t.push(left);
- t.push(p-1);
- }
- if (p+1<right)
- {
- t.push(p+1);
- t.push(right);
- }
- while(!t.empty())
- {
- int r = t.top();
- t.pop();
- int l = t.top();
- t.pop();
- p = partition(a, l, r);
- if (p-1>l)
- {
- t.push(l);
- t.push(p-1);
- }
- if (p+1<r)
- {
- t.push(p+1);
- t.push(r);
- }
- }
- }
- }
3.三路划分快速排序算法:
实现代码:
- void quickSort3Way(double a[], int left, int right)
- {
- if(left < right)
- {
- double x = a[right];
- int i = left-1, j = right, p = left-1, q = right;
- for (;;)
- {
- while (a[++i] < x) {}
- while (a[--j] > x) {if(j==left) break;}
- if(i < j)
- {
- swap(a[i], a[j]);
- if (a[i] == x) {p++; swap(a[p], a[i]);}
- if (a[j] == x) {q--; swap(a[q], a[j]);}
- }
- else break;
- }
- swap(a[i], a[right]); j = i-1; i=i+1;
- for (int k=left; k<=p; k++, j--) swap(a[k], a[j]);
- for (int k=right-1; k>=q; k--, i++) swap(a[i], a[k]);
- quickSort3Way(a, left, j);
- quickSort3Way(a, i, right);
- }
- }
4.测试代码:
- #include <iostream>
- #include <stack>
- #include <ctime>
- using namespace std;
- // 产生(a,b)范围内的num个随机数
- double* CreateRand(double a, double b, int num)
- {
- double *c;
- c = new double[num];
- srand((unsigned int)time(NULL));
- for (int i=0; i<num; i++)
- c[i] = (b-a)*(double)rand()/RAND_MAX + a;
- return c;
- }
- // 两路划分,获取中轴,轴左边数小于轴,轴右边数大于轴
- double partition(double* a, int left, int right)
- {
- ...
- }
- // 1.递归快速排序,利用两路划分
- void quickSort1(double* a, int left, int right)
- {
- ...
- }
- // 2.非递归快速排序,手动利用栈来存储每次分块快排的起始点,栈非空时循环获取中轴入栈
- void quickSort2(double* a, int left, int right)
- {
- ...
- }
- // 3.利用三路划分实现递归快速排序
- void quickSort3Way(double a[], int left, int right)
- {
- ...
- }
- void main()
- {
- double *a, *b, *c;
- int k=10000000;
- time_t start,end;
- a = CreateRand(0,1,k);
- b = CreateRand(0,1,k);
- c = CreateRand(0,1,k);
- start = clock();
- quickSort1(a,0,k-1);
- end = clock();
- cout<<"1.recursive "<<1.0*(end-start)/CLOCKS_PER_SEC<<" seconds"<<endl;
- start = clock();
- quickSort2(b,0,k-1);
- end = clock();
- cout<<"2.non-recursive "<<1.0*(end-start)/CLOCKS_PER_SEC<<" seconds"<<endl;
- start = clock();
- quickSort3Way(c,0,k-1);
- end = clock();
- cout<<"3.3 way "<<1.0*(end-start)/CLOCKS_PER_SEC<<" seconds"<<endl;
- cout<<endl;
- system("pause");
- }
result:
1.recursive 1.951 seconds
2.non-recursive 2.224 seconds
3.3 way 1.677 seconds
结果可以看出非递归算法由于需要手动进行算法过程中的变量保存,执行效率低于递归算法;3路划分算法利用少量多余的交换减少了快排的复杂度,执行效率高于传统2路快排算法。
- 快速排序
- 快速排序
- 快速排序
- 快速排序!
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- C语言学习03
- iostat命令
- EGit与Gerrit的联合使用
- 操作系统中作业、程序、进程、线程及管程的定义与联系
- ClassUtils 反射实现 笔记一文尽知
- 快速排序
- NOIp2009TG T2/Luogu P1072 Hankson的趣味题 解题报告
- jsp与js之间变量赋值问题
- Leetcode (295) Find Median from Data Stream
- 搭建Windows下的Cocos2d-3.X的开发环境
- 二分匹配续(hdu 1845,hdu 2063)
- 帮助别人(互惠)--别人报答的对比思考
- 直方图匹配
- CSS3快速上手之21:响应式+图片滤镜