其中分解的方法有多種,很容易引起混淆,下面逐一介紹。
1. Lomuto從左至右單向掃描版:參見編程珠璣
int partition1(int A[], int p, int r)
{
t = A[p]; // 首元素爲樞紐
int m = p;
for(i = p+1; i<=r; i++)
{ /* invariant: A[p+1...m] < A[p] && A[m+1...i-1]>=A[p] */
if( A[i] < t)
swap(A[++m], i)
}
swap(A[p],A[m]); //這次交換不可少
return m;
}
2. Lomuto從右至左單向掃描版:參見編程珠璣int partition2(int A[], int p, int r)
{
t = A[p]; // 首元素爲樞紐
int m = r+1;
for(i = r; i>=p; i--)
{ /* invariant: A[m...r] >= A[p] && A[m-1...i]<A[p] */
if( A[i] >= t)
swap(A[--m], i)
}
// swap(A[p],A[m]); //這次交換已經包含在for循環內
return m;
}
3. Lomuto從左至右單向掃描版:參見算法導論int partition3(int A[], int p, int r)
{
t = A[r]; // 尾元素爲樞紐
int m = p-1;
for(i = p; i<r; i++)
{
if( A[i] <= t)
swap(A[++m], i)
}
swap(A[r],A[m+1]); //這次交換不可少
return m+1;
}
上述三個算法的缺點是:當A數組所有元素相同時,n-1次劃分中每次
劃分都需要O(n)時間去掉一個元素,時間複雜度O(n*n)。
4. Hoare雙向掃描版:參見博客<結構之法>
int partition4(int A[],int p,int r) //雙向掃描
{
int key=A[p]; // 首元素爲樞紐
int i=p-1;
int j=r+1;
for(;;)
{
do{
j--;
}while(A[j]>key);
do{
i++;
}while(A[i]<key);
if(i<j)
{
swap(A[i],A[j]);
}
else
{
return j; //注意這裏的返回值是j。
}
}
}
5. Hoare變種:參見嚴蔚敏數據結構int partition5(int A[],int p,int r) //雙向掃描。
{
int key=A[p]; //以第一個元素爲主元
int i=p;
int j=r;
while(i<j)
{
while(key<=A[h] && i<j)
j--;
A[i]=A[j];
while(A[i]<=key && i<j)
i++;
A[j]=A[i];
}
A[i]=key;
return i; //注意這裏返回的是i
}
6. STL qsort 算法:參見侯捷STL源碼剖析
int partition6(int A[],int p,int r,int key) //雙向掃描。
{
//這裏的key可以是數組中任意一元素的值,但通常是首、尾、中間元素的中位數的值。
//這裏的r其實是數組最後元素的下一個元素,符合STL左閉右開的假定
while(true)
{
while(A[p]<key) ++p;
--r;
while(key<A[r]) --r;
if( !(p<r) ) return p; //注意這裏返回的是p
swap(A[p],A[r]);
++r;
}
}
其實我感覺小於號改成小於等於號也行,可能是STL出於泛化的考慮,數據有可能不支持小於等於號。以上是在看書和看博客過程中的一些思考,可能有些錯誤,僅記下來待以後看。