快速排序的三种实现方法 (C++)

快速排序的中心思想

       快速排序利用的是分治思想,将一个大数组的排序划分为多个小数组的排序,最后进行合并便是排序的结果。

      首先,需要从数组中选择一个主元,通常为数组的第一个元素或最后一个元素(好操作)。接下来的工作就是要将数组中的其他元素与主元进行对比,小于主元的元素放在主元的左边,大于主元的元素放在主元的右边。

      例如有数组 A[begin...end] 经过上述步骤后会得到A[begin...q-1]A[q]A[q+1...end]

      其中A[q]为主元,子数组 A[begin...q-1] 的所有元素小于主元,子数组A[q+1...end] 的所有元素大于主元。

      此时,能确定的就是A[q]的位置,并且该位置就是最终排序后A[q]的位置,不会再变。

      接下来要做的就是让两个子数组A[begin...q-1], A[q+1...end]重复上述步骤,直到每个子数组只剩一个元素,此时就是最终排序完成的数组。


      中午突然发现忘掉了快速排序的具体实现过程,下午赶快找空闲时间写一次。

      快速排序有很多种方法,首先我们要了解的是快速排序创始人 C. A. R. Hoare 的实现方法。

一. 快速排序1

      比如有数组{3,8,4,9,2,7,1},选择3为主元,有两个变量i,j 分别从数组头尾向中间滑动,每当j从尾开始找到小于主元的元素时停止,换i从头查找大于主元的元素,找到两个元素后交换两个元素的位置,直到i和j相等。(也可以用相反的方式,最终得到逆序的数组)

       例如{3,8,4,9,2,7,1},主元为3,j从尾搜索直到A[j]=1停止,i从头搜索直到A[i]=8停止,交换位置。

          →{3,1,4,9,2,7,8},接下来,j会一直搜索直到A[j]=2,i搜索到A[i]=4,交换位置。

          →{3,1,2,9,4,7,8},之后,j会搜索到j=i,此时交换主元和位置i的元素,也就是3和2。

          →{2,1,3,9,4,7,8}   这便是经过一次排序操作后的结果,主元3左边的子数组{2,1}全部小于主元,右边的子数组{9,4,7,8}全部大于主元。之后再对子数组进行相同的操作,直到最终排序完成。

二. 快速排序2

      这种排序方式是算法导论第三版书中的方法,与第一种方法类似(其实都差不多,思路相同实现方式不同而已)。

      同样使用{3,8,1,9,2,7,4},选择4为主元,有两个变量i,j 用来维持一段大于主元或小于主元的数组A[i+1,j],最后将主元与A[i+1]交换。

        比如有{3,8,1,9,2,7,4},主元为4,令i+1指向3,j指向3,j向后移动,每当遇到小于主元的数便会与位于i+1的元素交换,直到最后,此时i到j之间所有元素均大于主元,此时交换主元与i处的元素。

        例如{3,8,1,9,2,7,4},主元为4,i与j指向3,i+1后移指向8,j后移直到1,此时此时交换1和8.

           →{3,1,8,9,2,7,4},之后i不变,用来控制大于主元数组的头部,j后移直到A[j] = 2,交换2和8.

           →{3,1,2,9,8,7,4},此时i+1指向9,之后直至结束没有变化,交换i+1和主元。

           →{3,1,2,4,8,7,9},这便是经过一次排序操作后的结果,主元4左边的子数组{3,1,2}全部小于主元,右边的子数组{8,7,9}全部大于主元。之后再对子数组进行相同的操作,直到最终排序完成。(过程中i与j之间的元素全部大于主元)

三.快速排序3

        这种排序方式是上课时讲到的方法,这种方式主元不再是最后才进行移动。而是在比较过程中移动。

        比如有{3,8,1,9,2,7,4},令主元为3,有两个变量i与j,分别从头尾向中间进行扫描。这种方法是令j从尾向前扫描,知道遇到比主元小的元素,此时交换该元素与主元;之后令i从头开始扫描,直到遇到比主元大的值,交换该值与主元,最终得到结果便是一个元素均大于主元的子数组和一个元素均小于主元的子数组,并且此时主元所在的位置就是最终排序后该元素应在的位置。

        例如{3,8,1,9,2,7,4},主元为3,i指向头,j指向尾,j开始向前扫描,直到j指向2,交换2和3.

           →{2,8,1,9,3,7,4},之后i从头开始扫描,直到i指向8,交换8和3.

           →{2,3,1,9,8,7,4},之后j从上次j扫描的位置继续扫描,直到j=1,交换1和3.

           →{2,1,3,9,8,7,4},直至结束不再变化。这就是经过一次排序后的结果,主元3左边元素均小于3,右边元素均大于3。之后再多两边的子数组进行相同的操作,直到排序完成。



        下面是这三种方式的实现代码.

#include <iostream>
using namespace std;

int len = 0;		//数组长度

/**************************************    输出函数    ********************************************/
void _show(const int a[])
{
	for(int i=0;i<len;i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
}
/**************************************    交换次序函数  ********************************************/
void swap(int *a,int i,int j)
{
	int temp;
	temp = a[i];
	a[i]= a[j];
	a[j] = temp;
}
/**************************************    快速排序1   ********************************************/
int _partition(int a[], int p, int r)
{
	int x = a[r];
	int i = p-1;
	for(int j=p;j<=r-1;j++)
	{
		if(a[j]<=x)
		{
			i=i+1;
			swap(a,i,j);
		}
	}
	swap(a,i+1,r);
	return i+1;
}
void _firstsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _partition(a,first,last);
		_firstsort(a,first,q-1);
		_firstsort(a,q+1,last);
	}
}
/**************************************    快速排序2   ********************************************/
int _hoare(int a[], int p, int r)
{
	int x = a[p];
	int i = p;
	int j = r + 1;

	while(1)
	{
		while(a[--j]>x);
		while(a[++i]<x);

		if(i<j)
			swap(a,i,j);
		else
			break;
	}
	a[p] = a[j];
	a[j] = x;
	return j;
}
void _secondsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _hoare(a,first,last);
		_secondsort(a,first,q-1);
		_secondsort(a,q+1,last);

	}
}
/**************************************    快速排序3   ********************************************/
int _coursep(int a[], int p, int r)
{
	int u = p;
	int d = r;
	while(u<d)
	{
		while(a[u]<a[d]&&u<d)
			u++;
		swap(a,u,d);
		while(a[d]>a[u]&&u<d)
			d--;
		swap(a,u,d);
	}
	return u;
}
void _thirdsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _coursep(a,first,last);
		_thirdsort(a,first,q-1);
		_thirdsort(a,q+1,last);
	}
}

/**************************************     整理输出形式  ********************************************/
void _first(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_firstsort(a,first,last);
	cout << "排序后序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}
void _second(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_secondsort(a,first,last);
	cout << "排序后序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}
void _third(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_thirdsort(a,first,last);
	cout << "排序后序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}


/**************************************     MAIN      ********************************************/
int main()
{
	unsigned int flag = 0;
	unsigned int num = 0;
	cout << "快速排序测试......" << endl << endl;
	
	cout << "输入数组长度: ";
	cin >> len;
	int *arr = new int [len];
	
	cout << "输入数组元素: ";
	for(int i=0;i<len;i++)
	{
		cin >> arr[i];
	}
	
	while(1)
	{
		int *a = new int [len];
		for(int i = 0; i<len; i++)
		{
			a[i] = arr[i];
		}
		cout << "三种快速排序,选择一种(1,2,3, 4退出)" << endl;
		cin >> flag;
		while(flag<1||flag>4)
		{
			cout << "输入错误,重新输入: ";
			cin >> flag;
		}
		switch(flag){
			case 1: _first(a,0,len-1);break;
			case 2: _second(a,0,len-1);break;
			case 3: _third(a,0,len-1);break;
			case 4: return 0;
			default: cout << "未知错误" << endl;
		}
		delete[] a;
	}
	delete[] arr;
	return 0;
}

       本来是想写在小本子上记录下来,后来琢磨着就干脆写到这里吧,希望对算法的初学者们有一个较好的引路作用(希望没有误人子弟)。

       快速排序的解释,包括这段稚嫩的代码,其中一定存在没有解释清楚的地方,或者说不足之处,欢迎看到这篇文章的各位能够提出宝贵意见。


       转载注明出处哦:https://blog.csdn.net/lazyboy_/article/details/80242736



猜你喜欢

转载自blog.csdn.net/Lazyboy_/article/details/80242736