排序演算法大雜燴(一)——基礎排序

來源:互聯網
上載者:User
文章目錄
  • 1)插入排序
  •  
  • 2)希爾排序
  •  
  • 3)選擇排序
  •  
  • 4)冒泡排序
  •  
  • 5)計數排序
  •  
  • 6)基數排序
  •  
  • 7)歸併排序
一、前言排序演算法也是面試中常常提及的內容,問的最多的應該是快速排序、堆排序。這些排序演算法很基礎,但是如果平時不怎麼寫代碼的話,面試的時候總會出現各種bug。雖然思想都知道,但是就是寫不出來。本文打算對各種排序演算法進行一個匯總,像插入排序、冒泡排序、選擇排序等就簡單的介紹,重點關注快速排序和堆排序。需要提到的一點就是:插入排序,冒泡排序,歸併排序,計數排序都是穩定的排序,而其他排序則都是不穩定的。二、簡單排序1)插入排序插入排序是很基本的排序,特別是在資料基本有序的情況下,插入排序的效能很高,基本可以達到O(N)。當然其最壞情況和平均情況時間複雜度都是O(N^2)。代碼如下:
void insert_sort(int x[], int n){    int i, j;    for (i=1; i<n; i++) {        /*迴圈不變式:x[0...i-1]有序。每次迭代開始前,x[0...i-1]有序, 迴圈結束後i=n,x[0...n-1]有序*/        int key = x[i];        for (j=i; j>0 && x[j-1]>key; j--) {            x[j] = x[j-1];        }        x[j] = key;    }}
 2)希爾排序

希爾排序內部調用插入排序來實現,通過對N/2,N/4...1階分別排序,最後得到整體的有序。

void shell_sort(int a[], int n){for (int gap=n/2; gap>0; gap /=2) {for (int i=gap; i<n; i++) {int key = a[i], j;for (j=i; j>=gap && key<a[j-gap]; j -= gap) {a[j] = a[j-gap];}a[j] = key;}}}
 3)選擇排序選擇排序的思想就是第i次選取第i小的元素放在位置i。比如第1次就選擇最小的元素放在位置0,第2次選擇第二小的元素放在位置1。選擇排序最好和最壞時間複雜度都為O(N^2)。代碼如下:
void select_sort(int x[], int n){    int i, j, min, tmp;    for (i=0; i<n-1; i++) {        min = i;        for (j=i+1; j<n; j++) {            if (x[j] < x[min])                min = j;        }        if (min != i)            tmp = x[i], x[i] = x[min], x[min] = tmp;//交換x[i]和x[min]    }}
迴圈不變式:在外層迴圈執行前,x[0...i-1]包含a中最小的i個數,且有序。初始時,i=0,x[0...-1]為空白,顯然成立。每次執行完成後,x[0...i]包含x中最小的i+1個數,且有序。即第一次執行完成後,x[0...0]包含x最小的1個數,且有序。迴圈結束後,i=n-1,則x[0...n-2]包含x最小的n-1個數,且已經有序。所以整個數組有序。 4)冒泡排序冒泡排序時間複雜度跟選擇排序相同。其思想就是進行n-1趟排序,每次都是把最小的數上浮,像魚冒泡一樣。最壞情況為O(N^2)。代碼如下:
void bubble_sort(int x[], int n){    int tmp;    for (int i=0; i<n; i++) {        for (int j = n-1; j>=i+1; j--) {            if (x[j] < x[j-1])                tmp = x[j], x[j] = x[j-1], x[j-1] = tmp;        }       }   }

迴圈不變式:在迴圈開始迭代前,子數組x[0...i-1]包含了數組x[0..n-1]i-1個最小值,且是排好序的。對冒泡排序的一個改進就是在每趟排序時判斷是否發生交換,如果一次交換都沒有發生,則數組已經有序,可以不用繼續剩下的趟數直接退出。改進後代碼如下:

void bubble_sort_better(int x[], int n){    int tmp;    for (int i=0; i<n; i++) {        int sorted = 1;        for (int j = n-1; j>=i+1; j--) {            if (x[j] < x[j-1]) {                tmp = x[j], x[j] = x[j-1], x[j-1] = tmp;                sorted = 0;            }           }           if (sorted)            return ;    }   }
 5)計數排序

假定數組為A[0...n-1],數組中存在重複數字,數組中最大數字為k,建立兩個輔助數組B和C,B用於儲存排序後的結果,C用於儲存臨時值。時間複雜度為O(N),適用於數字範圍較小的數組。具體見代碼:

const int N = 5; //數字個數int b[N+1];void count_sort(int a[], int n, int k) //k為數組最大數字{    int c[k+1];  //輔助數組    for (int i=0; i<=k; i++)        c[i] = 0;    for (int j=0; j<n; j++)        c[a[j]] = c[a[j]] + 1; //C[i]包含等於i的元素個數    for (int i=1; i<=k; i++)        c[i] = c[i] + c[i-1];  //C[i]包含小於等於i的元素個數    for (int j=n-1; j>=0; j--) {        b[c[a[j]]-1] = a[j]; //結果存在B[0...N-1]中        c[a[j]] = c[a[j]] - 1;    }}
擴充:如果代碼中的 最後一個迴圈語句for (int j=n-1; j>=0; j--)改為for(int j=0; j<=n-1; j++)該代碼仍然正確,只是排序不再穩定。 6)基數排序基數排序的思想是對數字每一位分別排序( 注意這裡必須是穩定排序,比如計數排序等,否則會導致結果錯誤),最後得到整體排序。假定對N個數字進行排序,如果數字有d位,每一位可能的最大值為K,則每一位的穩定排序需要O(N+K)時間,總的需要O(d(N+K))時間,當d為常數,K=O(N)時,總的時間複雜度為O(N)。代碼省略。 7)歸併排序

歸併排序通過分治演算法,先排序好兩個子數組,然後將兩個子數組歸併。時間複雜度為O(NlgN)。代碼如下:

/*歸併排序代碼*/void merge_sort(int a[], int p, int r) {if (p < r) {int q = p+(r-p)/2;merge_sort(a, p, q);merge_sort(a, q + 1, r);merge(a, p, q, r);}}void merge(int a[], int start, int mid, int end) {int n1 = mid - start + 1;int n2 = end - mid;int left[n1], right[n2];int i, j;for (i = 0; i < n1; i++) /* left holds a[start..mid] */left[i] = a[start + i];for (j = 0; j < n2; j++) /* right holds a[mid+1..end] */right[j] = a[mid + 1 + j];i = j = 0;int k = start;while (i < n1 && j < n2) {if (left[i] < right[j])a[k++] = left[i++];elsea[k++] = right[j++];}while (i < n1) /* left[] is not exhausted */a[k++] = left[i++];while (j < n2) /* right[] is not exhausted */a[k++] = right[j++];}

擴充:歸併排序的非遞迴實現怎麼做?

歸併排序的非遞迴實現其實是最自然的方式,先兩兩合并,而後再四四合并等,就是從底向上的一個過程。代碼如下:

void merge_sort(int a[], int n){    int s=2,i;    while(s<=n){        i=0;        while(i+s<=n){            merge(a, i, i+s/2-1, i+s-1);            i+=s;        }        //處理末尾殘餘部分        merge(a, i, i+s/2-1, n-1);        s*=2;    }    //最後再從頭到尾處理一遍    merge(a, 0, s/2-1, n-1);}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.