归并排序
归并排序(mergeSort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治的思想。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,也称为二路归并。
1、首先考虑下如何将将二个有序数列合并。从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中搬移这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。(可参照链表面试题中:合并两个有序链表使之有序)。
2、解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
代码如下:(合并两个有序区间)
private static void merge(int[] array,int left,int mid,int right,int[] extra){
int i = left;
int j = mid;
int x = 0;
while (i < mid && j < right){
if (array[i] <= array[j]){
extra[x++] = array[i++];
}else{
extra[x++] = array[j++];
}
}
while (i < mid){
extra[x++] = array[i++];
}
while (j < right){
extra[x++] = array[j++];
}
for (int k = left; k < right; k++){
array[k] = extra[k -left];
}
}
归并排序代码如下:
private static void mergeSortInner(int[] array, int left, int right, int[] extra){
//1、平均切分
if(left == right -1){
return;
}
if (left >= right){
return;
}
int mid = left +(right -left)/2;
//2、分治处理所有两个小区间
mergeSortInner(array,left,mid,extra);
mergeSortInner(array,mid,right,extra);
//左右两个小区间已经有序
merge(array,left,mid,right,extra);
}
public static void mergeSort(int[] array){
int[] extra = new int[array.length];
mergeSortInner(array,0,array.length,extra);
}
归并排序总结:
归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。