[027]八大排序算法詳解——歸併排序

基本思想

n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果:

  1. 初始狀態:無序區爲R[1..n],有序區爲空。
  2. 第1趟排序: 在無序區R[1..n]中選出關鍵字最小的記錄R[k],將它與無序區的第1個記錄R[1] 交換,使R[1..1]和R[2..n]分別變爲記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。
  3. ……
  4. 第i趟排序: 第i趟排序開始時,當前有序區和無序區分別爲R[1..i-1]和R[i..n](1≤i≤n-1)。 該趟排序從當前無序區中選出關鍵字最小的記錄R[k],將它與無序區的第1個記錄R[i]交換,使R[1..i] 和R[i+1..n]分別變爲記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。

這樣,n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果。

算法實現

歸併排序算法,Java實現,代碼如下所示:

01 public abstract class Sorter {
02      public abstract void sort(int[] array);
03 }
04  
05 public class MergeSorter extends Sorter {
06  
07      @Override
08      public void sort(int[] array) {
09           int[] auxArray = new int[array.length];
10           mergeSort(array, auxArray, 0, array.length - 1);
11      }
12  
13      /**
14      * 基於分治思想,執行歸併排序
15      * @param low 待排序數組下標下界
16      * @param high 待排序數組下標上界
17      */
18      private void mergeSort(int[] array, int[] auxArray, int low, int high) {
19           int dividedIndex = 0// 分治位置索引變量
20           if (low < high) {
21                dividedIndex = (low + high) / 2// 計算分治位置(採用簡單的二分思想)
22                mergeSort(array, auxArray, low, dividedIndex); // 左側遞歸歸併排序
23                mergeSort(array, auxArray, dividedIndex + 1, high); // 右側遞歸歸併排序
24                merge(array, auxArray, low, dividedIndex, high); // 合併分治結果
25           }
26      }
27  
28      private void merge(int[] array, int[] auxArray, int low, int dividedIndex, int high) {
29           int i = low; // 指向左半分區數組的指針
30           int j = dividedIndex + 1// 指向右半分區數組的指針
31           int auxPtr = 0// 指向輔助區數組的指針
32           // 合併兩個有序數組:array[low..dividedIndex]與array[dividedIndex+1..high]。
33           while (i <= dividedIndex && j <= high) { // 將兩個有序的數組合並,排序到輔助數組auxArray中
34                if (array[i] > array[j]) { // 左側數組array[low..dividedIndex]中的array[i]大於右側數組array[dividedIndex+1..high]中的array[j]
35                     auxArray[auxPtr++] = array[j++];
36                else {
37                     auxArray[auxPtr++] = array[i++];
38                }
39           }
40           // 如果array[low..dividedIndex].length>array[dividedIndex+1..high].length,經過上面合併
41           // array[low..dividedIndex]沒有合併完,則直接將array[low..dividedIndex]中沒有合併的元素複製到輔助數組auxArray中去
42           while (i <= dividedIndex) {
43                auxArray[auxPtr++] = array[i++];
44           }
45           // 如果array[low..dividedIndex].length<array[dividedIndex+1..high].length,經過上面合併
46           // array[dividedIndex+1..high]沒有合併完,則直接將array[dividedIndex+1..high]中沒有合併的元素複製到輔助數組auxArray中去
47           while (j <= high) {
48                auxArray[auxPtr++] = array[j++];
49           }
50           // 最後把輔助數組auxArray的元素複製到原來的數組中去,歸併排序結束
51           for (auxPtr = 0, i = low; i <= high; i++, auxPtr++) {
52                array[i] = auxArray[auxPtr];
53           }
54      }
55 }

歸併排序算法,Python實現,代碼如下所示:

01 class Sorter:
02     '''
03     Abstract sorter class, which provides shared methods being used by
04     subclasses.
05     '''
06     __metaclass__ = ABCMeta
07     
08     @abstractmethod  
09     def sort(self, array):
10         pass
11  
12 class MergeSorter(Sorter):
13     '''
14     Merge sorter
15     '''
16         
17     def sort(self, array):
18         length = len(array)
19         # initialize auxiliary list
20         auxiliary_list = [0 for in range(length)]
21         self.__merge_sort(array, auxiliary_list, 0, length - 1)
22     
23     def __merge_sort(self, array, auxiliary_list, low, high):
24         dividedIndex = 0
25         if low<high:
26             dividedIndex = (low + high) // 2
27             self.__merge_sort(array, auxiliary_list, low, dividedIndex)
28             self.__merge_sort(array, auxiliary_list, dividedIndex + 1, high)
29             self.__merge(array, auxiliary_list, low, dividedIndex, high)
30             
31     def __merge(self, array, auxiliary_list, low, dividedIndex, high):
32         = low
33         = dividedIndex + 1
34         pointer = 0
35         while i<=dividedIndex and j<=high:
36             if array[i]>array[j]:
37                 auxiliary_list[pointer] = array[j]
38                 = + 1
39             else:
40                 auxiliary_list[pointer] = array[i]
41                 = + 1
42             pointer = pointer + 1
43         while i<=dividedIndex:
44             auxiliary_list[pointer] = array[i]
45             pointer = pointer + 1
46             = + 1
47         while j<=high:
48             auxiliary_list[pointer] = array[j]
49             pointer = pointer + 1
50             = + 1
51         # copy elements in auxiliary list to the original list
52         pointer = 0
53         = low
54         while i<=high:
55             array[i] = auxiliary_list[pointer]
56             = + 1
57             pointer = pointer + 1

排序過程

假設待排序數組爲array = {94,12,34,76,26,9,0,37,55,76,37,5,68,83,90,37,12,65,76,49},數組大小爲20,我們以該數組爲例,執行歸併排序的具體過程,如下所示:

01 [94,12,34,76,26,9,0,37,55,76,    37,5,68,83,90,37,12,65,76,49]
02 [94,12,34,76,26,    9,0,37,55,76]
03 [94,12,34,    76,26]
04 [94,12,    34]
05 [94,    12]
06 {12,    94}
07 {12,34,    94}
08 [76,    26]
09 {26,    76}
10 {12,26,34,    76,94}
11 [9,0,37,    55,76]
12 [9,0,    37]
13 [9,    0]
14 {0,    9}
15 {0,9,    37}
16 [55,    76]
17 {55,    76}
18 {0,9,37,    55,76}
19 {0,9,12,26,34,    37,55,76,76,94}
20 [37,5,68,83,90,    37,12,65,76,49]
21 [37,5,68,    83,90]
22 [37,5,    68]
23 [37,    5]
24 {5,    37}
25 {5,37,    68}
26 [83,    90]
27 {83,    90}
28 {5,37,68,    83,90}
29 [37,12,65,    76,49]
30 [37,12,    65]
31 [37,    12 ]
32 {12,    37 }
33 {12,37,    65 }
34 [76,    49 ]
35 {49,    76}
36 {12,37,49,    65,76}
37 {5,12,37,37,49,    65,68,76,83,90}
38 {0,5,9,12,12,26,34,37,37,37,    49,55,65,68,76,76,76,83,90,94}

上面示例的排序過程中,方括號表示“分解”操作過程中,將原始數組進行遞歸分解,直到不能再繼續分割爲止;花括號表示“歸併”的過程,將上一步分解後的數組進行歸併排序。因爲採用遞歸分治的策略,所以從上面的排序過程可以看到,“分解”和“歸併”交叉出現。

算法分析

  • 時間複雜度

對長度爲n的文件,需進行FLOOR(logn) 趟二路歸併,每趟歸併的時間爲O(n),故其時間複雜度無論是在最好情況下還是在最壞情況下均是O(nlgn)。

  • 空間複雜度

需要一個輔助向量來暫存兩有序子文件歸併的結果,故其輔助空間複雜度爲O(n),顯然它不是就地排序。

  • 排序穩定性

歸併排序是一種穩定的排序。

轉載原地址:http://shiyanjun.cn/archives/820.html


發佈了33 篇原創文章 · 獲贊 14 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章