快速排序

快速排序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 
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 
#include 
#include 
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 
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;
}



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

还是那句话:“加油!”


你可能感兴趣的:(排序,算法导论)