快速排序

来源:互联网 发布:php面向对象设计模式 编辑:程序博客网 时间:2024/06/05 09:32

快速排序quicksort)的期望运行时间是Θ(n lgn),而最坏情况为Θ(n2)

快速排序与归并排序一样,也是基于分治的想法的,分治过程有三个步骤:

1、分解   将一个数组一分为二

2、解决  递归调用分治过程,对分出的两个子数组排序

3、合并  这里要理解的是,因为两个子数组都是就地排序,所以合并的过程并不需要操作


在《算法导论》以及后面的思考题中,介绍了好几种快排版本,下面我主要实现了算法导论正文的版本、随机化版本及思考题7-1的最初的快排版本


(1)下面是算法导论版本的快排代码及注释解析:

/****Author: asd***Data: 2012/7/20***blog:http://blog.csdn.net/zhengjj_asd***quick-sort (算法导论版)*/#include <iostream>using namespace std;int size;  //size代表待排序元素个数//对数组输出void arr_display(int *a){for(int i = 0; i < size - 1; ++ i)cout << a[i] << ' ';cout << a[size - 1] << endl;}//交换void swap(int &a, int &b){int t = a; a = b; b = t;}//快排的关键函数,对子数组a[p..r]进行就地重排//以 key 即 a[r] 作为主元,围绕它划分子数组//使函数结束后,保证子数组 a[p..i] <= a[i + 1] <= a[i + 2 .. r], 其中a[r + 1] = key;//具体操作我会在这段代码结束时,贴上算法导论上的样例图解,不懂的可以顺着程序模拟下过程就明白了int Partition(int *a, int p, int r){int key = a[r];int i = p - 1;for(int j = p; j < r; ++ j){if(a[j] <= key){++ i;swap(a[i], a[j]);}}swap(a[i + 1], a[r]);return i + 1;}//采用分治的思想,将一个子数组就地排序后,按partition中的key的位置,分为左右两个元素个数更小的两个子数组//最后左右两个子数组合并时,因为对两个子数组是进行原地排序,所以并不需要任何合并操作void Quick_Sort(int *a, int p, int r){if(p < r){int q = Partition(a, p, r);//*******以下这段主要是为了在学习快排过程中,了解partition对原数组就地排序的作用********cout << "对第" << p + 1 << " 个元素到第 " << r + 1 << "个元素调用 Partition 结果为:";arr_display(a);//**************************************************************************Quick_Sort(a, p, q - 1);Quick_Sort(a, q + 1, r);}}int main(){int a[100];cout << "输入元素个数:";cin >> size;cout << "输入各个元素:";for(int i = 0; i < size; ++ i)cin >> a[i];cout << "排序开始..." << endl;Quick_Sort(a, 0, size - 1);cout << "排序结束,结果为:";arr_display();return 0;}

以下是算法导论中关于partition的原地排序过程的一个样例数组图例,看代码不能理解的话,可以就着下图顺着程序运行步骤理解下.



(2)接着是快排的随机化版本,以下是代码及其主要解析(我也偷懒下,如果是上面已出现的函数基本没什么大变化的话,我不会再进行注释)

/****Author: asd***Data: 2012/7/26***blog:http://blog.csdn.net/zhengjj_asd***Quick_Sort (随机化版本)*/#include <iostream>#include <cstdlib>#include <ctime>using namespace std;int size;//******************以下这段在上面代码一样******void arr_display(int *a){for(int i = 0; i < size - 1; ++ i)cout << a[i] << ' ';cout << a[size - 1] << endl;}void swap(int &a, int &b){int t = a; a = b; b = t;}int Partition(int *a, int p, int r){int key = a[r];int i = p - 1;for(int j = p; j < r; ++ j){if(a[j] <= key){++ i;swap(a[i], a[j]);}}swap(a[i + 1], a[r]);return i + 1;}//*****************以上一样************//求a ~ b中的一个随机数int Rand(int a, int b){return a + rand() % (b - a + 1);}//通过这个函数,将a[i]做为key,其中i是随机出来的值//思考题 7-5 所说的“三数取中”划分则是,随机三个元素出来,然后取其中的中值做为partition的key;int Rand_Partition(int *a, int p, int r){int i = Rand(p, r);swap(a[i], a[r]);return Partition(a, p, r);}//与上一个代码的Quick_Sort函数基本相同void Rand_Quick_Sort(int *a, int p, int r){if(p < r){int q = Rand_Partition(a, p, r);cout << "对第" << p + 1 << " 个元素到第 " << r + 1 << "个元素调用 Partition 结果为:";arr_display(a);Rand_Quick_Sort(a, p, q - 1);Rand_Quick_Sort(a, q + 1, r);}}int main(){//生成随机种子srand( (unsigned)time( NULL ) );int a[100];cout << "输入元素个数:";cin >> size;cout << "输入各个元素:";for(int i = 0; i < size; ++ i)cin >> a[i];cout << "排序开始..." << endl;Rand_Quick_Sort(a, 0, size - 1);return 0;}


(3)以下是最初的快排版本,主要的不同在于Partition函数的不同,但其目的基本是一样(这一个就没注释得那么详细了大笑):

/****Author: asd***Data: 2012/7/26***blog:http://blog.csdn.net/zhengjj_asd***Quick_Sort (Partition为最初的快排版本,Hoare)*/#include <iostream>using namespace std;int size;void arr_display(int *a){for(int i = 0; i < size - 1; ++ i)cout << a[i] << ' ';cout << a[size - 1] << endl;}void swap(int &a, int &b){int t = a; a = b; b = t;}//与算法导论版本唯一的不同就是partition的操作//两者目的全都是一样,不同的是Hoare_Partition过程是将主元key放入划分的两个子数组中的某一个中int Hoare_Partition(int *a, int p, int r){int key = a[p];int i = p - 1;int j = r + 1;while(1){while(a[-- j] > key);while(a[++ i] < key);if(i < j)swap(a[i], a[j]);elsereturn j;}}void Quick_Sort(int *a, int p, int r){if(p < r){int q = Hoare_Partition(a, p, r);cout << "对第" << p + 1 << " 个元素到第 " << r + 1 << "个元素调用 Partition 结果为:";arr_display(a);Quick_Sort(a, p, q - 1);Quick_Sort(a, q + 1, r);}}int main(){int a[100];cout << "输入元素个数:";cin >> size;cout << "输入各个元素:";for(int i = 0; i < size; ++ i)cin >> a[i];cout << "排序开始..." << endl;Quick_Sort(a, 0, size - 1);return 0;}



快排终于写完了,这一两周一直想早点写完,但是因为一些事总是不能去写,好纠结....

还是那句话:“加油!”