1. 程式人生 > >數據結構之排序

數據結構之排序

隨著 out lB emp 理解 判斷 結構 一位 順序

1. 插入排序

1.1 直接插入排序  

直接插入排序是將未排序的數據插入至已排好序序列的合適位置。   具體流程如下:   1、首先比較數組的前兩個數據,並排序;   2、比較第三個元素與前兩個排好序的數據,並將第三個元素放入適當的位置;   3、比較第四個元素與前三個排好序的數據,並將第四個元素放入適當的位置;    ......   4、直至把最後一個元素放入適當的位置。   假如有初始數據:25 11 45 26 12 78。   1、首先比較25和11的大小,11小,位置互換,第一輪排序後,順序為:[11, 25, 45, 26, 12, 78]。   2、對於第三個數據45,其大於11、25,所以位置不變,順序依舊為:[11, 25, 45, 26, 12, 78]。   3、對於第四個數據26,其大於11、25,小於45,所以將其插入25和45之間,順序為:[11, 25, 26, 45, 12, 78]。   .......   4、最終順序為:[11, 12, 25, 26, 45, 78]。   直接插入排序是穩定的。直接插入排序的平均時間復雜度為O(n2)。   Java 代碼實現如下:
技術分享圖片
 1     public void sort(int[] arr) {
 2         int tmp;
 3         for(int i = 1; i < arr.length; i++) {
 4             // 待插入數據
 5             tmp = arr[i];
 6             int j;
 7             for(j = i - 1; j >= 0; j--) {
 8                 // 判斷是否大於tmp,大於則後移一位
 9                 if(arr[j] > tmp) {
10                     arr[j+1] = arr[j];
11                 }else{
12                     break;
13                 }
14             }
15             arr[j+1] = tmp;
16             System.out.println(i + ":" + Arrays.toString(arr));
17         }
18     }
技術分享圖片

1.2 希爾排序(最小增量排序)

希爾排序嚴格來說是基於插入排序的思想,又被稱為縮小增量排序。

  具體流程如下:   1、將包含n個元素的數組,分成n/2個數組序列,第一個數據和第n/2+1個數據為一對...   2、對每對數據進行比較和交換,排好順序;   3、然後分成n/4個數組序列,再次排序;   4、不斷重復以上過程,隨著序列減少並直至為1,排序完成。   假如有初始數據:25 11 45 26 12 78。   1、第一輪排序,將該數組分成 6/2=3 個數組序列,第1個數據和第4個數據為一對,第2個數據和第5個數據為一對,第3個數據和第6個數據為一對,每對數據進行比較排序,排序後順序為:[25, 11, 45, 26, 12, 78]。   2、第二輪排序 ,將上輪排序後的數組分成6/4=1個數組序列,此時逐個對數據比較,按照插入排序對該數組進行排序,排序後的順序為:[11, 12, 25, 26, 45, 78]。   對於插入排序而言,如果原數組是基本有序的,那排序效率就可大大提高。另外,對於數量較小的序列使用直接插入排序,會因需要移動的數據量少,其效率也會提高。因此,希爾排序具有較高的執行效率。   希爾排序並不穩定,O(1)的額外空間,時間復雜度為O(N*(logN)^2)。 技術分享圖片
 1     public void sort(int[] arr) {
 2         // i表示希爾排序中的第n/2+1個元素(或者n/4+1)
 3         // j表示希爾排序中從0到n/2的元素(n/4)
 4         // r表示希爾排序中n/2+1或者n/4+1的值
 5         int i, j, r, tmp;
 6         // 劃組排序
 7         for(r = arr.length / 2; r >= 1; r = r / 2) {
 8             for(i = r; i < arr.length; i++) {
 9                 tmp = arr[i];
10                 j = i - r;
11                 // 一輪排序
12                 while(j >= 0 && tmp < arr[j]) {
13                     arr[j+r] = arr[j];
14                     j -= r;
15                 }
16                 arr[j+r] = tmp;
17             }
18             System.out.println(i + ":" + Arrays.toString(arr));
19         }
20     }
技術分享圖片

2. 交換排序

2.1 冒泡排序

原理:比較兩個相鄰的元素,將值大的元素交換至右端。

思路:依次比較相鄰的兩個數,將小數放在前面,大數放在後面。即在第一趟:首先比較第1個和第2個數,將小數放前,大數放後。然後比較第2個數和第3個數,將小數放前,大數放後,如此繼續,直至比較最後兩個數,將小數放前,大數放後。重復第一趟步驟,直至全部排序完成。

舉例說明:要排序數組:int[] arr={6,3,8,2,9,1};

第一趟排序:

    第一次排序:6和3比較,6大於3,交換位置: 3 6 8 2 9 1

    第二次排序:6和8比較,6小於8,不交換位置:3 6 8 2 9 1

    第三次排序:8和2比較,8大於2,交換位置: 3 6 2 8 9 1

    第四次排序:8和9比較,8小於9,不交換位置:3 6 2 8 9 1

    第五次排序:9和1比較:9大於1,交換位置: 3 6 2 8 1 9

    第一趟總共進行了5次比較, 排序結果: 3 6 2 8 1 9

---------------------------------------------------------------------

第二趟排序:

    第一次排序:3和6比較,3小於6,不交換位置:3 6 2 8 1 9

    第二次排序:6和2比較,6大於2,交換位置: 3 2 6 8 1 9

    第三次排序:6和8比較,6大於8,不交換位置:3 2 6 8 1 9

    第四次排序:8和1比較,8大於1,交換位置: 3 2 6 1 8 9

    第二趟總共進行了4次比較, 排序結果: 3 2 6 1 8 9

---------------------------------------------------------------------

第三趟排序:

    第一次排序:3和2比較,3大於2,交換位置: 2 3 6 1 8 9

    第二次排序:3和6比較,3小於6,不交換位置:2 3 6 1 8 9

    第三次排序:6和1比較,6大於1,交換位置: 2 3 1 6 8 9

    第二趟總共進行了3次比較, 排序結果: 2 3 1 6 8 9

---------------------------------------------------------------------

第四趟排序:

    第一次排序:2和3比較,2小於3,不交換位置:2 3 1 6 8 9

    第二次排序:3和1比較,3大於1,交換位置: 2 1 3 6 8 9

    第二趟總共進行了2次比較, 排序結果: 2 1 3 6 8 9

---------------------------------------------------------------------

第五趟排序:

    第一次排序:2和1比較,2大於1,交換位置: 1 2 3 6 8 9

    第二趟總共進行了1次比較, 排序結果: 1 2 3 6 8 9

---------------------------------------------------------------------

最終結果:1 2 3 6 8 9

---------------------------------------------------------------------

由此可見:N個數字要排序完成,總共進行N-1趟排序,每i趟的排序次數為(N-i)次,所以可以用雙重循環語句,外層控制循環多少趟,內層控制每一趟的循環次數,即

技術分享圖片

    public static void BubbleSort(int[] arr) {
        int temp;//定義一個臨時變量
        for(int i=0;i<arr.length-1;i++){//冒泡趟數
            for(int j=0;j<arr.length-i-1;j++){
                if(arr[j+1]<arr[j]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
技術分享圖片

2.2 快速排序

單單看以上解釋還是有些模糊,可以通過實例來理解它,下面通過一組數據來進行排序過程的解析:

原數組:{3,7,2,9,1,4,6,8,10,5}

期望結果:{1,2,3,4,5,6,7,8,9,10}

花了點時間擼了下面這張快速排序示意圖:

技術分享圖片

Demo步驟解析:

1.一開始選定數組的最後一個元素5作為基準值,也就是最終排序結果應該是以5為界限劃分為左右兩邊。

2.從左邊開始,尋找比5大的值,然後與5進行調換(因為如果比5小的值本來就應該排在5前面,比5大的值調換之後就去到了5的後面),一路過來找到了7,將7與5調換,結束此次遍歷。

3.從右邊開始,由於7已經是上一輪排好序的便不再動它,從10開始,一路向左遍歷,尋找比5小的值,然後與5進行調換(因為如果比5大的值本來就應該排在5後面,比5小的值調換之後就去到了5的後前面),一路過來找到了4,將4與5調換,結束此次遍歷。

4.從左邊開始,由於3和4都是前兩輪已經排好序的便不再動它,從2開始,一路向右遍歷,尋找比5大的值,然後與5進行調換(道理同步驟2),一路過來找到了9,將9與5調換,結束此次遍歷。

5.從右邊開始,由於排在9後面的那幾個數字都是上幾輪排好序的便不再動它,從1開始,一路向右遍歷,尋找比5小的值,然後與5進行調換(道理同步驟3),一下子就找到了1,將1與5調換,結束此次遍歷。

6.這個時候,發現5的左右兩邊都是排好序了的,所以結束此輪排序,5的左右兩邊抽出來各自進行下一輪的排序,規則同上,直到無法再拆分下去,即完成了整體的快速排序。

Java代碼
  1. /**
  2. * 快速排序
  3. * @author IT_ZJYANG
  4. */
  5. public class QuickSort {
  6. /**
  7. * 將數組的某一段元素進行劃分,小的在左邊,大的在右邊
  8. * @param a
  9. * @param start
  10. * @param end
  11. * @return
  12. */
  13. public static int divide(int[] a, int start, int end){
  14. //每次都以最右邊的元素作為基準值
  15. int base = a[end];
  16. //start一旦等於end,就說明左右兩個指針合並到了同一位置,可以結束此輪循環。
  17. while(start < end){
  18. while(start < end && a[start] <= base)
  19. //從左邊開始遍歷,如果比基準值小,就繼續向右走
  20. start++;
  21. //上面的while循環結束時,就說明當前的a[start]的值比基準值大,應與基準值進行交換
  22. if(start < end){
  23. //交換
  24. int temp = a[start];
  25. a[start] = a[end];
  26. a[end] = temp;
  27. //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值右邊),因此右邊也要同時向前移動一位
  28. end--;
  29. }
  30. while(start < end && a[end] >= base)
  31. //從右邊開始遍歷,如果比基準值大,就繼續向左走
  32. end--;
  33. //上面的while循環結束時,就說明當前的a[end]的值比基準值小,應與基準值進行交換
  34. if(start < end){
  35. //交換
  36. int temp = a[start];
  37. a[start] = a[end];
  38. a[end] = temp;
  39. //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值左邊),因此左邊也要同時向後移動一位
  40. start++;
  41. }
  42. }
  43. //這裏返回start或者end皆可,此時的start和end都為基準值所在的位置
  44. return end;
  45. }
  46. /**
  47. * 排序
  48. * @param a
  49. * @param start
  50. * @param end
  51. */
  52. public static void sort(int[] a, int start, int end){
  53. if(start > end){
  54. //如果只有一個元素,就不用再排下去了
  55. return;
  56. }
  57. else{
  58. //如果不止一個元素,繼續劃分兩邊遞歸排序下去
  59. int partition = divide(a, start, end);
  60. sort(a, start, partition-1);
  61. sort(a, partition+1, end);
  62. }
  63. }
  64. }

數據結構之排序