1、基本思想数组
归并排序,将当前序列分红若干个小的有序序列,而后逐个合并成更大的有序序列。这里所谓的若干个小的有序序列便是将序列分割成n个长度为1的序列,而后两两合并成长度为二的有序序列。而后在将这长度为二的有序序列合并为长度为四的有序序列。依次类推,最终达到原序列长度,这样,排序就完成了。这实际上是归并排序递归回溯过程的描述。归并排序的正序描述能够是这样,将序列分红两个子序列,对两个子序列进行归并排序,而后将两个子序列合并到原序列中。dom
2、实现步骤测试
归并排序,有两个须要解决的问题:1、如何划分子区间。2、如何合并子区间。spa
划分子区间:code
这里采用两路归并排序,即将当前序列划分红两个子序列。blog
合并子区间:排序
因为子区间是有序的,因此在合并过程当中不会有很大的复杂度,一次遍历便可。递归
思想已经陈述完毕,下面看代码,有详细注释。get
3、实现代码io
随机数组测试类 点击这里
package sort; import sort.util.*; public class MergingSort implements ISort{ //private static int[] c = null; //将有序序列a[left] ~ a[middle]和a[middle+1] ~ a[right]合并到数组b中,返回数组b private void merge(int[] a , int left , int middle , int right) { int[] b = new int[a.length]; for(int i = 0; i < a.length; i++) { //将数组a复制到b中 b[i] = a[i]; } int i = left , j = middle + 1 , k = left; while(i <= middle && j <= right) { //合并过程,选择较小的,逐个赋值。 if(b[i] < b[j]) a[k++] = b[i++]; else a[k++] = b[j++]; } //循环结束,说明有一个有序序列已经遍历完毕 while(i <= middle) {a[k++] = b[i++];} //将剩余的部分直接复制到a数组中 while(j <= right) {a[k++] = b[j++];} //这两个循环只有一个能被执行 } //对a[left] ~ a[right]进行归并排序,排序后的结果放在b[]中 private void mergeSort(int[] a , int left , int right) { if(left != right) { //当进行归并排序的数组只有一个元素 int middle = (left + right) / 2; //划分红两部分进行归并 mergeSort(a , left , middle); //左边部分进行归并排序 mergeSort(a , middle+1 , right); //右边部分进行归并排序 merge(a , left , middle , right); //左右排序完成后进行合并 } } public void sort(int[] array){ mergeSort(array , 0 , array.length-1); } public static void main(String[] args) { int[] array = RandomArrayGenerator.getRandomArray(100 , 30); SortTestHelper.test(new MergingSort() , array); } }
测试结果:
4、总结分析
时间复杂度:O(n log n) 合并复杂度为n,递归过程的复杂度为log2n
空间复杂度:O(n) 须要一个辅助数组
稳定性:稳定。
八大排序中其他两个nlogn复杂度的堆排序和快速排序是不稳定的,较普通排序更快的希尔排序也是不稳定的。本文所讲的归并排序倒是稳定的,并且效率也很可观。
本文我的编写,水平有限,若有错误,恳请指出,欢迎讨论分享