合并排序也可以用打牌的过程来说明,假设桌面上朝上放着两摞已经排好序的牌,现在要将这两摞已排好序的牌合成一摞,首先,取两摞中位于最上面的两张中最小的一张并将其加入到新的一摞中,然后接着从两摞中再取一张最小的加入到新的一摞中,因为第二张,肯定比第一张要大,因此要加入到第一张的后面才行。
从上面可以看出,合并排序是利用分治法进行排序的算法,直观地操作如下:
分解:将n个元素分成各含n/2个元素的子序列;
解决:用合并排序法对两个子序列进行递归地排序;
合并:合并两个已排序的子序列以得到排序结果。
我就不写伪代码了,直接用Java将其实现的代码如下:
1 /** 2 * 合并两个排好的序列 3 * @param A 4 * int数组 5 * @param p 6 * 起始位置 7 * @param q 8 * 中间位置 9 * @param r 10 * 终止位置 11 * @param isInc 12 * isInc 是否升序,true为升序,false为降序 13 */ 14 private void merge(int[] A, int p, int q, int r, boolean isInc) { 15 int nLeft = q - p + 1; 16 int nRight = r - q; 17 int[] left = new int[nLeft]; 18 int[] right = new int[nRight]; 19 int i = 0, j = 0, k = 0; 20 for (i = 0; i < nLeft; i++) { 21 left[i] = A[p + i]; 22 } 23 for (j = 0; j < nRight; j++) { 24 right[j] = A[q + j + 1]; 25 } 26 i = 0; 27 j = 0; 28 for (k = p; k <= r; k++) { 29 if (isInc ^ (left[i] <= right[j])) { 30 A[k] = right[j]; 31 j++; 32 } else { 33 A[k] = left[i]; 34 i++; 35 } 36 37 if (i == nLeft) { 38 k++; 39 for (; j < nRight; j++) { 40 A[k] = right[j]; 41 k++; 42 } 43 } 44 if (j == nRight) { 45 k++; 46 for (; i < nLeft; i++) { 47 A[k] = left[i]; 48 k++; 49 } 50 } 51 } 52 }
1 /** 2 * 合并排序 3 * @param A 4 * int数组 5 * @param p 6 * 起始位置 7 * @param r 8 * 终止位置 9 * @param isInc 10 * 是否升序,true为升序,false为降序 11 */ 12 private void mergeSort(int[] A, int p, int r, boolean isInc) { 13 int q = 0; 14 if (p < r) { 15 q = (p + r) / 2; 16 mergeSort(A, p, q, isInc); 17 mergeSort(A, q + 1, r, isInc); 18 merge(A, p, q, r, isInc); 19 } 20 }
合并排序不是原地进行排序的,时间复杂度为O(nlgn)。