跳转至

C. 归并排序

C. 归并排序

更新日期: 2020-05-13


1. 基本原理

归并排序十分简单。它的步骤如下:

  • (1) 将数组从中间一分为二。
  • (2) 将左数组排序。
  • (3) 将右数组排序。
  • (4) 将排序之后的左右数组归并为一个数组。

可以看到归并排序是一个递归的过程。它的实质性排序操作就是那个将两个小的有序数组归并为一个大的数组的过程。

这个操作也很简单。可以归结为:

  • (1) 比较两个小数组的头部元素。
  • (2) 将较小的元素从那个小数组中移除,放入结果数组中。
  • (3) 重复上述过程,直至两个小数组中的元素被全部移入结果数组中。

2. 代码示范(Java)

代码示范

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public class MergeSort {    

    // 归并排序 
    public static void mergeSort(int[] numArray) {  

        // 执行归并排序   
        _mergeSort(numArray, 0, numArray.length - 1);   
    }   

    // 对指定起始位置和终了位置的数组执行归并排序    
    private static void _mergeSort(int[] numArray, int startIndex, int endIndex) {  

        // 如果数组长度为1,则不需要再分  
        if (startIndex == endIndex) {   
            return; 
        }   

        // 将数组平分为两个数组   
        int centIndex = (startIndex + endIndex) / 2;    

        // 分别将两个数组排序    
        _mergeSort(numArray, startIndex, centIndex);    
        _mergeSort(numArray, centIndex + 1, endIndex);  

        // 将排序后的两个数组合并为一个   
        _mergeArray(numArray,startIndex, centIndex, endIndex);  
    }   

    // 将两个数组合并为一个   
    private static void _mergeArray(int[] numArray, int startIndex, int centIndex, int endIndex) {  
            
        // 创建存放排序结果的临时数组    
        int[] rstArray = new int[endIndex - startIndex + 1];    

        // 从两个数组头部开始,依次挑出较小的元素,放入结果数组中  
        int rstIndex = 0;   
        int leftIndex = startIndex; 
        int rightIndex = centIndex + 1; 
        while (true) {  

            // 如果左边数组头部较小   
            if (numArray[leftIndex] <= numArray[rightIndex]) {  

                // 将左边数组头部元素放入结果数组  
                rstArray[rstIndex] = numArray[leftIndex];   
                // 将结果数组当前索引加1  
                rstIndex++; 
                // 将左数组索引指向下一个元素    
                leftIndex++;    
                // 如果左数组已空,则把右数组剩余的内容复制到结果数组中,排序完毕  
                if (leftIndex > centIndex) {    

                    // 拷贝数组 
                    _copyArray(numArray, rightIndex, endIndex, rstArray, rstIndex); 
                    // 排序完毕,退出循环    
                    break;  
                }   
                
            // 如果右边数组头部较小   
            } else {    

                // 将右边数组头部元素放入结果数组  
                rstArray[rstIndex] = numArray[rightIndex];  
                // 将结果数组当前索引加1  
                rstIndex++; 
                // 将右数组索引指向下一个元素    
                rightIndex++;   
                // 如果右数组已空,则把左数组剩余的内容复制到结果数组中,排序完毕  
                if (rightIndex > endIndex) {    

                    // 拷贝数组 
                    _copyArray(numArray, leftIndex, centIndex, rstArray, rstIndex); 
                    // 排序完毕,退出循环    
                    break;  
                }   
            }   
        }   

        // 将排序后的结果放回原数组 
        _copyArray(rstArray, 0, rstArray.length - 1, numArray, startIndex); 
    }   

    // 拷贝数组 
    private static void _copyArray(int[] srcArray, int srcStartIndex, int srcEndIndex,  
        int[] rstArray, int rstStartIndex) {    
            
            // 计算拷贝长度   
            int length = srcEndIndex - srcStartIndex + 1;   

            for (int i = 0; i < length; i++) {  

                rstArray[rstStartIndex + i] = srcArray[srcStartIndex + i];  
            }   
    }   
}