基本思想
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用
分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
综上可知:
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
归并排序算法复杂度O(n logn)。
public class MergeSort {
/*
* 归并算法:先将数组分成两半,然后对着两半数组递归归并,递归条件是数组长度大于1;
* 最后得到的两个排好序的数组最后再进行归并,得到排序结果
*/
public static void mergeSort(int[] list){
if(list.length > 1){
int[] firstHalf = new int[list.length / 2];
System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
mergeSort(firstHalf);
int secondHalfLength = list.length - list.length / 2;
int[] secondHalf = new int[list.length - list.length / 2];
System.arraycopy(list, list.length / 2, secondHalf, 0, secondHalfLength);
mergeSort(secondHalf);
int[] tmp = merge(firstHalf,secondHalf);
System.arraycopy(tmp, 0, list, 0, tmp.length);
}
}
/*
* merge方法是将list1和list2两个有序数组进行归并;
* 方法是构造一个输出数组,长度为l1.length + l2.length
* 然后依次遍历l1、l2
* 将较小者赋给输出数组
*/
public static int[] merge(int[] list1,int[] list2){
int[] tmp = new int[list1.length + list2.length];
int current1 = 0; // for list1
int current2 = 0; // for list2
int current3 = 0; // for tmp
while(current1 < list1.length && current2 < list2.length){
if(list1[current1] < list2[current2]){
tmp[current3 ++] = list1[current1 ++];
}
else
tmp[current3 ++] = list2[current2 ++];
}
while(current1 < list1.length){
tmp[current3 ++] = list1[current1 ++];
}
while(current2 < list2.length){
tmp[current3 ++] = list2[current2 ++];
}
return tmp;
}
public static void main(String[] args){
int[] list = {2,9,5,4,8,1,6,7};
mergeSort(list);
for(int element : list){
System.out.println(element);
}
}
}
使用场景
归并排序多用于需要外部排序的场景,除此之外当内部排序需要保证稳定性时也采用归并排序(不要求稳定性的内部排序一般采用快排或者堆排序,前者在待排序序列基本有序时效率低,后者堆的维护是个问题)