一.算法思想:
假設要對某數組進行由小->大排序
(1) 分解: 對於亂序數組a[R](存取範圍[0->R],有R+1個數),取一個基準元素a[P](一般以第一個數即a[0]爲基準),確定某個Partition(位置)Q ,使a[Q]右邊的數都大於等於a[P],a[Q]左邊的數都小於等於a[P].
(2)遞歸分治:分解之後,數組變成3部分 a[0]-a[Q],a[Q],a[Q+1]-a[R]. a[Q]只有一個元素,以它爲標杆,對a[0]->a[Q]和a[Q+1]->a[R]分別執行步驟(1)
二.例子示例:
數 組: 0 1 2 3 4 5 6
原序列: 7 12 9 8 5 2 3⑴.令P=0,取標杆a[P]爲7作爲基準,把a[0]存起來,記x=a[0];
令i=P+1,i開始向右邊走,找到>=7的數,此時i停留在下標1處
令j=R,j開始向左移動,找到<=7的數,則j停留在下標6處,如果i<j,交換a[i],a[j];
數 組: 0 1 2 3 4 5 6
現序列: 7 3 9 8 5 212
繼續執行步驟⑴,i到下標2處,j到下標5處,如果i<j,交換a[i],a[j]
數 組: 0 1 2 3 4 5 6現序列: 7 3 2 8 5 9 12
繼續執行步驟⑴,i到下標3處,j到下標4處,如果i<j,交換a[i],a[j]
數 組: 0 1 2 3 4 5 6現序列: 7 3 2 5 8 9 12
其中,i,j的移動在循環中(見後續代碼),如果找不到符合條件的數,會一直移動,直到i=r,則數組遍歷完畢,i不再移動,此時i到了下標6處
而j繼續移動,5符合條件,來到下標3處 ,但由於i>=j條件不成立,不交換a[i],a[j],此時交換a[P],a[j],j=3
數 組: 0 1 2 3 4 5 6現序列: 5 3 2 7 8 9 12
到此一個小分割就結束了,返回j下標Q=3,可以看出a[0->(j-1)]都小於或等於標杆x,即7,a[j+1->R]都大於或等於x.
後續可按上續步驟執行,
a[0]-a[Q]:
數 組: 0 1 2現序列: 5 3 2
x=0,i向右走,i=1,直到i=2,j向左找,找到a[j]<=x停止,此時j在下標2處,但由於i<j條件不成立,不交換a[i],a[j],此時交換a[P],a[j],則
數 組: 0 1 2現序列: 2 3 5
a[Q+1]-a[R]:
數 組: 3 4 5 6現序列: 7 8 9 12
同理,由於一直不滿足條件,i走到下標6處 j走到下標3處,此時i>j,執行交換a[P],a[j],原序列不變,算法結束
所以最終序列爲:
數 組: 0 1 2 3 4 5 6現序列: 2 3 5 7 8 9 12
三.源代碼:
#include<iostream>
using namespace std;
int Partition(int a[],int P, int R);
void Quicksort(int a[],int P, int R)
{
if(P<R)
{
int Q = Partition(a,P,R);
Quicksort(a,P,Q-1);
Quicksort(a,Q+1,R);
}
}
int Partition(int a[], int P, int R)
{
int i=P,j=R+1;//由於i,j先移動 提前加一位,但是以a[0]爲標杆,a[0]不參與比較,i不用先減1,可見★代碼處
int x=a[P];
while(true){
while(a[++i]<x&&i<R); //★ ++在前,先移動i再比較,所以初始i=P 此處目的是把i移動到a[i]>=x處或者i到最後一位停止.
while(a[--j]>x); //把i移動到a[i]<=x處
if(i>=j) break; //當i>=j大小標杆劃分完成
swap(a[i],a[j]);
}
swap(a[P],a[j]);
return j; //返回分界標杆
}
void main()
{
int a[7]= {7,12,9,8,5,2,3};
cout<<"原序列:\n";
for (int i = 0; i < 7; i++)
{
cout<<a[i]<<" ";
}
Quicksort(a,0,6); //此處傳第三個參注意爲n-1,n爲待排序數個數,因爲下標從0開始
cout<<"\n現序列:\n";
for (int i = 0; i < 7; i++)
{
cout<<a[i]<<" ";
}
}
四.運行結果:
參考資料:《計算機算法設計與分析》 p25
五.時間複雜度:
快速排序每次將待排序數組分爲兩個部分,如果理想,每一次都將待排序數組劃分成等長兩個部分,則需要logn次劃分。
平均需要(nlogn)