//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;
}
快速排序算法C++實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.