您的位置:首页 > 其它

快速排序

2012-07-26 11:45 176 查看
快速排序(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]);
else
return 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;
}


快排终于写完了,这一两周一直想早点写完,但是因为一些事总是不能去写,好纠结....
还是那句话:“加油!”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: