归并排序(Merge Sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并操作(Merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。归并排序有多路归并排序、两路归并排序 , 可用于内排序,也可以用于外排序。这里仅对内排序的两路归并方法进行讨论。
归并排序的步骤如下:
1)Divide: 将待排序序列(原问题)分成两个规模大致相等的子序列(子问题);
2)Conquer: 递归地排序两个子序列,当子序列规模足够小的时候直接完成排序;
3)Combine: 合并两个已序的子序列得到原序列的排序结果。
动画演示可以参照这个网址。
对于归并排序,最重要的就是归并操作。对于归并操作,可作如下理解:
1)针对输入的两段等合并的有序子序列,我们申请两个变量,分别对它们进行备份;
2)将这两段序列有序地合并到原序列中。因为这段序列是有序的,所以,当我们要判断将哪一个数据填入原序列时,只需判断两段序列中位置最低、且尚未被填入原序列的数据的大小,再将较小的数据填入原序列就可以了。
归并操作定义如下:
void MergeSort::merge(int low, int mid, int high)
数组arr从low到mid有序,从mid+1到high有序,合并这两部分,使得从low到high有序,且这个有序序列仍然放在arr的从low到high下标里。
一个比较详细的程序如下:
1 void MergeSort::mergesort(int low, int high) 2 { 3 if (high <= low) return; 4 5 int mid = (low + high) / 2; 6 mergesort(low, mid); 7 mergesort(mid + 1, high); 8 merge(low, mid, high); 9 } 10 11 void MergeSort::merge(int low, int mid, int high) 12 { 13 int nOfLeft = mid - low + 1; 14 int nOfRight = high - mid; 15 int * copyOfLeft = new(nothrow) int[nOfLeft]; 16 int * copyOfRight = new(nothrow) int[nOfRight]; 17 assert(copyOfLeft != nullptr); 18 assert(copyOfRight != nullptr); 19 20 // Copy left part 21 int i; 22 for (i = 0; i < nOfLeft; i++) 23 { 24 copyOfLeft[i] = arr[i + low]; 25 } 26 27 // Copy right part 28 int j; 29 for (j = 0; j < nOfRight; j++) 30 { 31 copyOfRight[j] = arr[j + mid + 1]; 32 } 33 34 // 在这里需要意识到的一个问题:copyOfLeft及copyOfRight已经是“有序”序列 35 // Merge 36 i = 0; 37 j = 0; 38 for (int k = low; k < high + 1; k++) 39 { 40 if (i > nOfLeft - 1) 41 { 42 arr[k] = copyOfRight[j]; 43 j++; 44 } 45 else if (j > nOfRight - 1) 46 { 47 arr[k] = copyOfLeft[i]; 48 i++; 49 } 50 else if (less(copyOfLeft[i], copyOfRight[j])) 51 { 52 arr[k] = copyOfLeft[i]; 53 i++; 54 } 55 else 56 { 57 arr[k] = copyOfRight[j]; 58 j++; 59 } 60 } 61 62 delete[] copyOfLeft; 63 delete[] copyOfRight; 64 }