1. 程式人生 > >八大排序經典演算法(圖解+參考原始碼)

八大排序經典演算法(圖解+參考原始碼)

概述

排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。

我們這裡說說八大排序就是內部排序。


    當n較大,則應採用時間複雜度為O(nlog2n)的排序方法:快速排序、堆排序或歸併排序序。

   快速排序:是目前基於比較的內部排序中被認為是最好的方法,當待排序的關鍵字是隨機分佈時,快速排序的平均時間最短;

1.插入排序—直接插入排序(Straight Insertion Sort)

基本思想:

將一個記錄插入到已排序好的有序表中,從而得到一個新,記錄數增1的有序表。即:先將序列的第1個記錄看成是一個有序的子序列,然後從第2個記錄逐個進行插入,直至整個序列有序為止。

要點:設立哨兵,作為臨時儲存和判斷陣列邊界之用。

直接插入排序示例:


如果碰見一個和插入元素相等的,那麼插入元素把想插入的元素放在相等元素的後面。所以,相等元素的前後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,所以插入排序是穩定的。

演算法的實現:

  1. void print(int a[], int n ,int i){  
  2.     cout<<i <<":";  
  3.     for(int j= 0; j<8; j++){  
  4.         cout<<a[j] <<" "
    ;  
  5.     }  
  6.     cout<<endl;  
  7. }  
  8. void InsertSort(int a[], int n)  
  9. {  
  10.     for(int i= 1; i<n; i++){  
  11.         if(a[i] < a[i-1]){               //若第i個元素大於i-1元素,直接插入。小於的話,移動有序表後插入
  12.             int j= i-1;   
  13.             int x = a[i];        //複製為哨兵,即儲存待排序元素
  14.             a[i] = a[i-1];           //先後移一個元素
  15.             while(x < a[j]){  //查詢在有序表的插入位置
  16.                 a[j+1] = a[j];  
  17.                 j--;         //元素後移
  18.             }  
  19.             a[j+1] = x;      //插入到正確位置
  20.         }  
  21.         print(a,n,i);           //列印每趟排序的結果
  22.     }  
  23. }  
  24. int main(){  
  25.     int a[8] = {3,1,5,7,2,4,9,6};  
  26.     InsertSort(a,8);  
  27.     print(a,8,8);  
  28. }  

效率:

時間複雜度:O(n^2).

其他的插入排序有二分插入排序,2-路插入排序。

 2. 插入排序—希爾排序(Shell`s Sort)

希爾排序是1959 年由D.L.Shell 提出來的,相對直接排序有較大的改進。希爾排序又叫縮小增量排序

基本思想:

先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。

操作方法:

  1. 選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  2. 按增量序列個數k,對序列進行k 趟排序;
  3. 每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

希爾排序的示例:

演算法實現:

我們簡單處理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n為要排序數的個數

即:先將要排序的一組記錄按某個增量dn/2,n為要排序數的個數)分成若干組子序列,每組中記錄的下標相差d.對每組中全部元素進行直接插入排序,然後再用一個較小的增量(d/2)對它進行分組,在每組中再進行直接插入排序。繼續不斷縮小增量直至為1,最後使用直接插入排序完成排序。

  1. void print(int a[], int n ,int i){  
  2.     cout<<i <<":";  
  3.     for(int j= 0; j<8; j++){  
  4.         cout<<a[j] <<" ";  
  5.     }  
  6.     cout<<endl;  
  7. }  
  8. /** 
  9.  * 直接插入排序的一般形式 
  10.  * 
  11.  * @param int dk 縮小增量,如果是直接插入排序,dk=1 
  12.  * 
  13.  */
  14. void ShellInsertSort(int a[], int n, int dk)  
  15. {  
  16.     for(int i= dk; i<n; ++i){  
  17.         if(a[i] < a[i-dk]){          //若第i個元素大於i-1元素,直接插入。小於的話,移動有序表後插入
  18.             int j = i-dk;     
  19.             int x = a[i];           //複製為哨兵,即儲存待排序元素
  20.             a[i] = a[i-dk];         //首先後移一個元素
  21.             while(x < a[j]){     //查詢在有序表的插入位置
  22.                 a[j+dk] = a[j];  
  23.                 j -= dk;             //元素後移
  24.             }  
  25.             a[j+dk] = x;            //插入到正確位置
  26.         }  
  27.         print(a, n,i );  
  28.     }  
  29. }  
  30. /** 
  31.  * 先按增量d(n/2,n為要排序數的個數進行希爾排序 
  32.  * 
  33.  */
  34. void shellSort(int a[], int n){  
  35.     int dk = n/2;  
  36.     while( dk >= 1  ){  
  37.         ShellInsertSort(a, n, dk);  
  38.         dk = dk/2;  
  39.     }  
  40. }  
  41. int main(){  
  42.     int a[8] = {3,1,5,7,2,4,9,6};  
  43.     //ShellInsertSort(a,8,1); //直接插入排序
  44.     shellSort(a,8);           //希爾插入排序
  45.     print(a,8,8);  
  46. }  

希爾排序時效分析很難,關鍵碼的比較次數與記錄移動次數依賴於增量因子序列d的選取,特定情況下可以準確估算出關鍵碼的比較次數和記錄的移動次數。目前還沒有人給出選取最好的增量因子序列的方法。增量因子序列可以有各種取法,有取奇數的,也有取質數的,但需要注意:增量因子中除1 外沒有公因子,且最後一個增量因子必須為1。希爾排序方法是一個不穩定的排序方法。

3. 選擇排序—簡單選擇排序(Simple Selection Sort)

基本思想:

在要排序的一組數中,選出最小(或者最大)的個數與第1個位置的數交換;然後在剩下的數當中再找最小(或者最大)的與第2個位置的數交換,依次類推,直到第n-1個元素(倒數第二個數)和第n個元素(最後個數)比較為止。

簡單選擇排序的示例:

 

操作方法:

第一趟,從n 個記錄中找出關鍵碼最小的記錄與第一個記錄交換;

第二趟,從第二個記錄開始的n-1 個記錄中再選出關鍵碼最小的記錄與第二個記錄交換;

以此類推.....

第i 趟,則從第i 個記錄開始的n-i+1 個記錄中選出關鍵碼最小的記錄與第i 個記錄交換,

直到整個序列按關鍵碼有序。


演算法實現:

  1. void print(int a[], int n ,int i){  
  2.     cout<<"第"<<i+1 <<"趟 : ";  
  3.     for(int j= 0; j<8; j++){  
  4.         cout<<a[j] <<"  ";  
  5.     }  
  6.     cout<<endl;  
  7. }  
  8. /** 
  9.  * 陣列的最小值 
  10.  * 
  11.  * @return int 陣列的鍵值 
  12.  */
  13. int SelectMinKey(int a[], int n, int i)  
  14. {  
  15.     int k = i;  
  16.     for(int j=i+1 ;j< n; ++j) {  
  17.         if(a[k] > a[j]) k = j;  
  18.     }  
  19.     return k;  
  20. }  
  21. /** 
  22.  * 選擇排序 
  23.  * 
  24.  */
  25. void selectSort(int a[], int n){  
  26.     int key, tmp;  
  27. 相關推薦

    八大排序經典演算法圖解+參考原始碼

    概述 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。 我們這裡說說八大排序就是內部排序。     當n較大,則應採用時間複雜度為O(

    【筆記】大數乘法之Karatsuba演算法 Java BigInteger原始碼

    BigInteger與uint[] 用uint[]來表示非負大數,其中陣列開頭是大數的最高32位,陣列結尾是大數最低32位。其與BigInteger的轉換方法 /// <summary> /// <see cref="uint"/>陣列轉為非負大整數 /// <

    【筆記】大數乘法之古典演算法 Java BigInteger原始碼

    BigInteger與uint[] 用uint[]來表示非負大數,其中陣列開頭是大數的最高32位,陣列結尾是大數最低32位。其與BigInteger的轉換方法 /// <summary> /// <see cref="uint"/>陣列轉為非負大整數 /// <

    史上最容易理解的《十大經典演算法動態圖展示

    十大經典排序演算法 部分內容引用自:https://www.cnblogs.com/onepixel/articles/7674659.html 感謝作者貢獻,如需刪除請聯絡本人! 0、排序演算法說明 0.1 排序分類   非線性時間比較類排序:通過比較來

    【筆記】大數乘法之Schönhage–Strassen演算法 Java BigInteger原始碼

    BigInteger to/from uint[] 用uint[]來表示非負大數,其中陣列開頭是大數的最高32位,陣列結尾是大數最低32位。 /// <summary> /// <see cref="uint"/>陣列轉為非負大整數 /// <

    拉格朗日插值演算法附c++原始碼

    C++程式實現Lagrange插值公式     Lagrange插值公式,是屬於數值分析方面的內容。此處我想用C++語言程式來實現n各插值節點插值公式的求解,並求出在某一個插值節點對應的函式值。   對於Lagrange插值演算法的基本思想,在這裡我只想略提兩點,一個是拉格朗

    SSM專案實踐:實現簡易網盤系統思路+參考原始碼

    一、專案主要功能 1、類似於百度雲,使用者可以在網盤中新建多層資料夾,並可以上傳檔案、下載檔案、刪除檔案、刪除資料夾(裡面所有檔案也會隨之刪除) 2、提供檔案分類功能,可根據字尾名將檔案分成視訊、圖片、音樂等。 3、使用者可以分享檔案,分享的檔案可以在分享

    最快速的“高斯”模糊演算法附Android原始碼

    1:高斯模糊演算法(參考:http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html) 所謂的模糊演算法就是當前畫素點和周圍畫素點進行加權均值之後的結果替換當前畫素值。因此均值模糊是最簡單的,只要將周圍的畫素點

    【資料結構與演算法】模式匹配——從BF演算法到KMP演算法附完整原始碼

    模式匹配子串的定位操作通常稱為串的模式匹配。模式匹配的應用很常見,比如在文書處理軟體中經常用到的查詢功能。我們用如下函式來表示對字串位置的定位:int index(const string &T

    十大經典排序演算法動圖演示 十大經典排序演算法動圖演示

    十大經典排序演算法(動圖演示)   0、演算法概述 0.1 演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性

    常見14種經典排序演算法Java程式碼實現

    尊重原創,轉載請標明出處   http://blog.csdn.net/abcdef314159 ,想了解更多演算法題可以關注微信公眾號“資料結構和演算法”,每天一題為你精彩解答。 一,氣泡排序 排序演算法其實有很多,氣泡排序基本上算是最簡單的一種

    java學習-排序及加密簽名時資料排序方式 十大經典排序演算法(動圖演示 Java Comparator字元排序(數字、字母、中文混合排序) 編寫高質量程式碼:改善Java程式的151個建議(第5章:陣列和集合___建議70~74)

    排序有兩種 1. 類實現comparable介面呼叫List.sort(null)或Collections.sort(List<T>)方法進行排序 jdk內建的基本型別包裝類等都實現了Comparablel介面,預設是使用自然排序,即升序排序 自定義類實現Comparable介面必須要實現c

    十大經典排序演算法動圖演示轉載

    0、演算法概述 0.1 演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基於比較排

    7中排序演算法學習總結圖解+程式程式碼

    我們通常所說的排序演算法往往指的是內部排序演算法,即資料記錄在記憶體中進行排序。 排序演算法大體可分為兩種:     一種是比較排序,時間複雜度O(nlogn) ~ O(n^2),主要有:氣泡排序,選擇排序,插入排序,歸併排序,堆排序,快速排序等。     另一種是非比較排

    【資料結構與演算法】內部排序之四:歸併排序和快速排序含完整原始碼

    前言      之所以把歸併排序和快速排序放在一起探討,很明顯兩者有一些相似之處:這兩種排序演算法都採用了分治的思想。下面來逐個分析其實現思想。歸併排序實現思想       歸併的含義很明顯就是將兩個或者兩個以上的有序表組合成一個新的有序表。歸併排序中一般所用到的是2-路歸併

    十大經典排序演算法動圖演示

    0、演算法概述 0.1 演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基於比較排序的時間下界,以線性時間執行,因

    【java】十大經典排序演算法動圖演示

    0,演算法概述 0.1演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突

    經典演算法:選擇排序

    昨天我們學習了經典中的經典,氣泡排序,今天我們來學習另一個經典演算法:選擇排序。 一、演算法描述 掃描所有的元素,得到最小(最大·)的元素,並將最小(最大)的元素與左邊第一個元素進行交換。再掃描除第一個位置以外的所有元素,得到最小(最大)元素,與左邊第二

    十大經典排序演算法帶動圖演示

    https://www.cnblogs.com/onepixel/articles/7674659.html https://www.cnblogs.com/eniac12/p/5329396.html 0.3 相關概念 穩定:如果a原本在b前面,而a=b

    java經典演算法氣泡排序和選擇排序

    氣泡排序: 氣泡排序的基本思想就是對相鄰的兩個元素進行排序,按照需求條件進行元素交換,依次排列,每一次排序都將最大或最小的元素按照順序依次排到最後一位,就像水中的氣泡一樣最大的氣泡浮在 最上面