數據結構與算法之歸併、快速排序

數據結構與算法之歸併、快速排序

  這是排序問題中的兩個重要且基礎的排序算法。之所以拿來一起介紹使用爲他倆有着異曲同工之妙,只要理解了歸併排序,就知道了快排是咋回事的了。
 歸併排序就是從局部無序變有序,最後全局無序變有序。基本思想就是先倆倆一組,通過合併排序,保證組內有序後,我們在將相鄰的兩組合並排序(將兩組鏈接並排序)成爲新的一組。然後再合併排序,再依次循環,直到一組的長度是整個待排序數組的長度。
 傳統的排序算法就是寫兩個嵌套的循環,然後一個個的對比,那麼此時的算法的時間複雜度就是O(nn),當要求排序的數組是非常大的時候,這是不可接受的。而歸併排序的時間複雜度是O(nlogn),顯然是優於傳統的排序算法。
  代碼實現:
1,我們先設計出合併排序代碼,即將兩組數組合並的同時進行排序。

const int maxn=100;
void merge(int a[],int l1,int r1,int l2,int  r2){
    int temp[maxn];
    int i=l1;
    int j=l2;
    int index=i;
    while(i<=r1&&j<=r2){
        if(a[i]<a[j]){
            j++;
            
            temp[i]=a[i];
            index+=1;
        }
        else{
            i++;
            temp[index]=a[j];
            index+=1;
        }
    }
    if(i<=r1){
        for(int k=r1;k<=r1;k++){
            temp[index]=a[k];
            index+=1;
        }
    }
    if(j<=r2){
        for(int k=r2;k<=r2;k++){
            temp[index]=a[k];
            index+=1;
        }

    }
    for(int i=l1;i<=r2;i++){
        a[i]=temp[i];
    }
}

 歸併排序的非遞歸實現:

void mergesort(int a[]){
for(int step=1;step<=n/2;step=step*2){
    for(int i=0;i<n;i=i+step;){
        merge(a,i,i+step-1,i+step,min(n,i+2*step-1))
    }
}
}

  遞歸實現:

void mergesort(int a[],int left ,int right){
    if(left<right){
        int mid=(right+left)/2;
        mergesort(a,left,mid);
        mergesort(a,mid+1,right);
        merge(a,left,mid,mid+1,right);//相當於二叉樹的後序遍歷
    }
}

 注意遞歸代碼如果看不懂的話,可以結合二叉樹的後序遍歷,來畫一下二叉搜索樹模擬一下。
  下面我們在介紹一下快速排序。第一步是選擇主元,那啥是主元呢?說白了就是待排序的那個元素。第二步是將主元放在正確的位置。下面結合一個例子:
待排序的數組:5 7 2 3 6 ,要求按增序順序

排序過程:將5作爲主元,然後核心思想就是將大於5的放在5的右邊,小於5的放在5的左邊。操作後就變爲:3 2 5 7 6。
我們發現現在離成功進了一步,因爲元素5的位置已經正確。繼續觀察,元素5兩側的序列仍是無序狀態,所以我們以5爲界限,拆成兩個子序列,然後對兩個子序列分別再進行一次,仍然選擇子序列的第一個元素爲主元。。。。。依次進行,直至子序列的長度爲1。代表排序完成。所以不難算出該算法的時間複雜度爲O(n*logn)。
  快速排序代碼如下:



 爲啥說有點相似呢?因爲他倆都有二分的一影子,前者是數量二分,後者是位置二分。他倆又是不同的,歸併排序“目光短淺”,他一開始就讓小段小段的有序,直至後來全局有序。而快速排序“目光長遠”,先讓混沌無序的數組變得有一點有序,即有一個元素處於正確的位置,然後整體有序。
  另外當數組中的元素越隨機時,快速排序算法的效率越高。特別的,當待排序的數組已經是增序或者減序時,該算法的時間複雜度是O(n*n),該算法完全退化爲一般的排序算法(即相當於兩層for循環)。因爲每次的子序列就是它母序列本身。
 以下是快速排序的遞歸實現的代碼:

void qucksort(int a[],int left,int right){
    int temp;
    a[left]=temp;
    int i=left;
    int j=right;
    int mid;
    while(i<j){
        while(a[j]>=temp&&i<j){
            j--;
        }
        a[i]=a[j];
        while(a[i]<temp&&i<j){
            i++;
        }
        a[j]=a[i];
    }
    mid=j;
    a[j]=temp;
    qucksort(a,left,mid-1);
    qucksort(a,mid+1,left);
}


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