1. 程式人生 > >排序演算法5之快速排序

排序演算法5之快速排序

快速排序

很早就聽說了快速排序的大名,然後看演算法導論的相關視訊也感覺講的很有意思,現在總結一下。針對待排序陣列{a1,a2an}快速排序可以分解為三步:

  1. 尋找基準數,比較通常就是選擇待排序的首專案或者中間專案;
    2.根據與基準數的大小關係, 將待排序陣列分成兩個子序列:{b1,b2bq1}{cq+1,cn}。其中{b1,b2bq1}均小於基準數,{cq+1,cn}均大於基準數,這樣基準數的位置就確定了在q處。
  2. 然後利用遞迴對兩個子序列進行排序。

下圖是對步驟2的介紹,只是該圖是將基準元素設定為最後一個元素,i和j的意義分別是,j作為遍歷指標遍歷從左往右遍歷陣列,i記錄小於等於基準元素的位置,當j指向的元素小於等於基準元素時,就交換(i+1)和j指向的元素,同時i++。當j指向最後基準元素時,交換(i+1)和j指向元素的位置,返回i就是上面提到的q:
這裡寫圖片描述

另外一種方法是,基準元素指向首專案,然後i和j分別指向首專案和尾專案。j先從右向左遍歷,直至遇到某專案小於等於基準元素,交換i和j指向的專案大小;然後i從從左向右遍歷,直至遇到某個專案大於基準元素,交換i和j指向的專案大小。當i和j相等時,停止遍歷,返回i或者j就是上面提到的q。下面的code是我按照原理二寫的。

#include<iostream>
using namespace std;

int quickSort(int* p,int start,int end)
{
    int i=start,j=end;
    int tmp=p[i];
    bool
flag=true; while(i<j) { if(p[j]<=tmp&&flag) { p[i]=p[j]; flag=false; } if(flag) j--; if(p[i]>tmp&&(!flag)) { p[j]=p[i]; flag=true; } if(!flag) i++; } p[i]=tmp; return
i; } void QuickSort(int* p,int start,int end) { if(start<end) { int index=quickSort(p,start,end); QuickSort(p,start,index-1); QuickSort(p,index+1,end); } } int main() { int data[10]={5,4,3,2,1,2,3,7,10,11}; QuickSort(data,0,9); for(int i=0;i<sizeof(data)/sizeof(data[0]);i++) cout<<"第"<<(i+1)<<"個專案:"<<data[i]<<endl; return 0; }

code可以進行優化:

int quickSort(int* p,int start,int end)
{
    int i=start,j=end;
    int tmp=p[i];
    bool flag=true;
    while(i<j)
    {
        while(i<j&&p[j]>tmp)
            j--;
        if(i<j)
            p[i]=p[j];
        while(i<j&&p[i]<=tmp)
            i++;
        if(i<j)
            p[j]=p[i];
    }
    p[i]=tmp;
    return i;
}

下面是按照第一種原理寫出來的code,感覺比第二種確實要簡單一些。

void swap(int& a, int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
int quickSort(int* p, int start, int end)
{
    int index = start - 1;
    int baseNum = p[end];
    for (int i = start; i <= end; i++)
    {
        if (p[i] <= baseNum)
        {
            swap(p[++index], p[i]);
        }
    }
    return index;
}

效能分析
時間複雜度:就平均效能而言,快速排序被認為是目前最好的一種內部排序,通常快排的平均時間複雜度是Ωnlog(n),但是若待排序陣列已經排序好了,或者幾乎是有序的,那麼快速排序將退化為氣泡排序,時間複雜度Ωn2。所以這種情況一般會先隨機打亂陣列或者隨機選擇基準元素的位置。

空間複雜度:最壞情況下,若每趟排序之後,樞軸位置均偏向子序列的一端(有序),棧的最大深度為Ωn。如果在一趟劃分之後比較分割所得兩部分的長度,且先對長度短的子序列中的記錄進行快速排序,則棧的最大深度可降為Ωlogn

快速排序是不穩定排序,就拿最後的實現方式來說明,快排只能保證從待排序陣列的左邊界到基準元素的位置之間的元素是穩定的,但是無法保證從基準元素的位置到待排序陣列的右邊界是穩定的。