归并排序是采用分治法的一个非常典型的应用。本质是将序列不断分成小的序列,分开排序后逐步合并成完整序列。
1.代码实现
以java递归实现为例:
public class MergeSort { public static int[] mergeSort(int[] nums, int start, int end) { if (start == end) return new int[] { nums[start] }; int mid = start + (end - start) / 2; int[] leftArr = mergeSort(nums, start, mid); //左有序数组 int[] rightArr = mergeSort(nums, mid + 1, end); //右有序数组 int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组 int m = 0, i = 0, j = 0; //这个循环是用来对比当前左右两组有序数组最当前最小值,并且插入到新的数组中,其中一个数组插完后停止循环 while (i < leftArr.length && j < rightArr.length) { newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++]; } //以下两个循环是用来判断左右两个有序数组中,是否有在下标后仍然存在元素的数组,如果有,继续往后移动下标,并且把新元素插入到新数组 //值得注意的是,这两个循环只会走其中一个(即存在两组数中最大的那个数组) while (i < leftArr.length) newNum[m++] = leftArr[i++]; while (j < rightArr.length) newNum[m++] = rightArr[j++]; return newNum; } public static void main(String[] args) { int[] nums = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 10 }; int[] newNums = mergeSort(nums, 0, nums.length - 1); for (int x : newNums) { System.out.print(x+" "); } } }
2.数据运行解析
数据的分解示例如下
[9 8 7 6 5 4 3 2 10] -> [9 8 7 6 5] [4 3 2 10] //先二分 -> [9 8 7] [6 5] [4 3 2 10] //先对左边再二分 -> [9 8] [7] [6 5] [4 3 2 10] //先对左边再二分 -> [8 9] [7] [6 5] [4 3 2 10] //对单个元素排序 9 8 -> [7 8 9 ] [6 5] [4 3 2 10] //递归回上一层对有序的8 9 和 单个元素7 排序 -> [7 8 9 ] [5 6] [4 3 2 10] //对当前的右边单个元素排序 6 5 -> [5 6 7 8 9 ] [4 3 2 10] //递归回上一层对有序的 7 8 9 和 5 6 排序 -> [5 6 7 8 9 ] [4 3] [2 10] ......
3.复杂度分析
传统归并排序的最优,最差,平均时间复杂度都是O(nlogn),空间复杂度为T(n)
如果在对比插入之前判断左右两个有序数组的其中一个最大值是否小于另一组的最小值,则在完全有序的序列的情况下,最优时间复杂度为O(n)(上述代码未实现)。
参考资料:
1)https://baike.baidu.com/item/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/1639015?fr=kg_qa#reference-[1]-90797-wrap
2)https://www.runoob.com/w3cnote/merge-sort.html