归并排序
归并排序主要运用分治法的思想,对待排序列进行排序。分治法的思想主要是将问题规模变小,
逐一求解,从而得到整体的解。
运用分治法解决问题主要有三个步骤:
分解(Divide): 将原问题分解为一系列子问题。
解决 (Conquer): 递归求解子问题,如果子问题足够小,可以直接得到答案;
合并 (Merge) :将子问题的结果合并成原问题的解。
归并排序运用分治的思想,可将问题分解为n/k的子问题,n为问题的规模,k为划分的大小。一般取k=2,也称二路归并。
二路归并按照分治法的步骤:先将n个元素划分为n/2的子序列。在递归对子序列进行排序。最后合并两个子序列的结果。如下:
n
n/2 n/2
n/4 n/4 n/4 n/4
.... .... ... .. .. ...
1 . ............................................. 1 问题规模为1,不用排序,与相邻元素比较合并成上一层的子序列。
可以通过递归树来对二路归并算法有直观的了解。
时间复杂度:划分子问题的时间为log2 N,排序时间为N,总的时间复杂度为nlog2 n。
java实现:
public class Merge_Sort{
public static void main(String[] args){
int[] unsorted = new int[]{3,2,5,1,7};
MergeSort(unsorted,0,unsorted.length-1);
for(int num:unsorted){
System.out.print("排序后:"+num+" ");
}
//归并排序函数Divide && Conquer 步骤1,2
private static void MergeSort(int unsorted[],int p,int r){
if(p<r){
int q = (p+r)/2;
MergeSort(unsorted,p,q);//递归调用,划分子问题
MergeSort(unsorted,q+1,r);
Merge(unsorted,p,q,r); //合并
}
}
//合并函数Merge 步骤3
private static void Merge(int unsorted[],int p,int q, int r){
int n1 = q-p+1; //q为待排数组中值,p为待排数组头,r为待排数组尾 p<=q<=r
int n2 = r-q;
int[] left = new int[n1+1];//待合并的左子序列,这里采用二路归并
int[] right = new int[n2+1];//右子序列;
for(int i = 0; i < n1;i++){
left[i] = unsorted[p+i-1];//左子序列为待排序列的前半部分
}
for(int j = 0; j < n2;j++){
right[j] = unsorted[q+j];
}
left[n1+1] = Integer.Max_Value;//设置哨兵位;
right[n2+1] = Integer.Max_Value;
int i = 0;
int j = 0;
for(int k = p; p < r;k++){
if(left[i] <= right[j]){
unsorted[k] = left[i];
i = i+1;
}else{
unsorted[k] = right[j];
j = j+1;
}
}
}