快速排序算法C++實現

//quick sort
//STL中也有現成的快速排序算法,內部實現採用了以下技巧
//1)樞軸的選擇採取三數取中的方式
//2)後半段採取循環的方式實現
//3)快速排序與插入排序結合
#include<vector>
#include<iostream>
#include<algorithm>

using namespace std;

//這一版本是最簡單實現版本,對於快速排序的優化主要有以下幾個方面:
//1)樞軸的選擇,若樞軸選取不全適,比如,若每次遞歸時,兩個子區間中的一個爲空,則快速排序將退化爲冒泡排序
//關於樞軸的選擇有多種:取最後一個元素、取第一個元素、三數取中、九數取中、隨機值等
//2)另一方面是對迭代過程的優化,減少交換次數,減少遞歸深度等;
template<class type>
int partion1(vector<type>& vec,int start,int end)
{//快速排序的核心部分
	//取最後一個作爲樞軸和第一個作爲樞軸程序類似,以下是取最後一個元素作爲樞軸
	int key=vec[end];
	int fast,slow;
	fast=slow=start;

	//用兩個指針的移動實現
	for(;fast<end;++fast)
	{
		if(vec[fast]<key)
		{
			if(fast!=slow)
			{
				int tmp=vec[slow];
				vec[slow]=vec[fast];
				vec[fast]=tmp;
			}
			slow++;
		}
	}
	int tmp=vec[slow];
	vec[slow]=vec[end];
	vec[end]=tmp;
	return slow;
}

//三數取中
template<class type>
int midNumber(type a,type b,type c)
{
	int big1=max(a,b);
	int big2=max(a,c);
	int big3=max(b,c);

	return min(big1,min(big2,big3));
}

template<class type>
int partion2(vector<type>& vec,int start,int end)
{
	//3數取中和9數取中的方式,保證了一定隨機性,以下是3數取中的方式
	int key=midNumber(vec[start],vec[(start+end)/2],vec[end]);

	int midNumPos=0;
	if(key==vec[start])
		midNumPos=start;
	else if(key==vec[end])
		midNumPos=end;
	else
		midNumPos=(start+end)/2;

	vec[midNumPos]=vec[end];
	vec[end]=key;

	//現在採用一種和上一種方案不同的交換方式
	while(start<end)
	{//樞軸的位置一直在改變
		while(start<end && vec[start]<=key)
			start++;

		int tmp=vec[start];
		vec[start]=vec[end];
		vec[end]=tmp;

		while(start<end && vec[end]>=key)
			end--;

		tmp=vec[start];
		vec[start]=vec[end];
		vec[end]=tmp;
	}

	return start;
}

template<class type>
int partion3(vector<type>& vec,int start,int end)
{//取隨機數的方法
	int keyNumPos=start+rand()%(end-start);
	int tmp=vec[keyNumPos];
	vec[keyNumPos]=vec[end];
	vec[end]=tmp;

	int key=vec[end];
	while(start<end)
	{//樞軸的位置一直在改變
		while(start<end && vec[start]<=key)
			start++;

		tmp=vec[start];
		vec[start]=vec[end];
		vec[end]=tmp;

		while(start<end && vec[end]>=key)
			end--;

		tmp=vec[start];
		vec[start]=vec[end];
		vec[end]=tmp;
	}
	return start;
}
//以上是三種對樞軸的優化方法,無非就是避免快速排序惡化
//以下是避免不必要的交換過程
template<class type>
int partion4(vector<type>& vec,int start,int end)
{//取隨機數的方法
	int keyNumPos=start+rand()%(end-start);
	int tmp=vec[keyNumPos];
	vec[keyNumPos]=vec[end];
	vec[end]=tmp;

	int key=vec[end];
	while(start<end)
	{//觀察可知,交換的過程中,總有一個數是key,所以當需要賦key值時可以直接跳過,於是可以減少賦值操作
		while(start<end && vec[start]<=key)
			start++;

		vec[end]=vec[start];//end以start覆蓋

		while(start<end && vec[end]>=key)
			end--;

		vec[start]=vec[end];//start以end覆蓋
	}
	vec[start]=key;
	return start;
}


template<class type>
void qSort1(vector<type>& vec,int start,int end)
{
	if(start>=end)return;
	int index=partion4(vec,start,end);//key
	qSort1(vec,start,index-1);
	qSort1(vec,index+1,end);
}

//遞歸過程需要出棧入棧,成本較高,而且可能棧溢出,如果可能的話最好以循環方式代替遞歸
template<class type>
void qSort2(vector<type>& vec,int start,int end)
{
	if(start>=end)return;
	
	int index;//key
	while(start<end)
	{//後半段的遞歸過程以循環代替,相當於減小了遞歸深度
		index=partion4(vec,start,end);//key
		qSort2(vec,start,index-1);
		start=index+1;
	}
}


//當處理的數據量比較小時,插入排序的成本可能比快速排序成本更低,所以考慮在數據量較小時採用插入排序

/*template<class type>
void qSort3(vector<type>& vec,int start,int end)
{
	if(start>=end)return;
	
	int index;//key
	if(end-start>VALUE)
	{	
		while(start<end)
		{//後半段的遞歸過程以循環代替,相當於減小了遞歸深度
			index=partion4(vec,start,end);//key
			qSort3(vec,start,index-1);
			start=index+1;
		}
	}
	else
	{
		insertSort(vec,start,end);
	}
}*/

template<class type>
void quickSort(vector<type>& vec)
{
	int length=vec.size();
	qSort2(vec,0,length-1);
}

int main()
{
	int a[10]={1,5,9,0,6,3,2,7,8,4};
	vector<int> vec(a,a+10);

	quickSort(vec);

	for(int i=0;i<vec.size();++i)
		cout<<vec[i]<<"  ";
	cout<<endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章