1.归并排序简介
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2.归并操作
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
3.代码实现
package sort;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args){
int[] arr = {8,3,2,6,7,1,5,4};//创建待排序数组
int[] temp = new int[arr.length];//创建一个长度为arr.length的临时中转数组,避免递归时产生新的空间
System.out.println("待排序数组:"+ Arrays.toString(arr));
resolve(arr,0,arr.length-1,temp);
System.out.println("归并排序后的数组:"+ Arrays.toString(arr));
}
/*
①分解(resolve)和合并
*/
public static void resolve(int[] arr,int left,int right,int[] temp){
if (left <right){
int mid = (left+right)/2 ;
//分解
resolve(arr,left,mid,temp);//递归调用分解左边序列
resolve(arr,mid+1,right,temp);//递归调用分解右边序列
//合并
merge(arr,left,mid,right,temp);//将左右两边的有序序列合并
}
}
/*
②合并操作
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//左边有序数列的初始索引
int j = mid+1;//右边有序数列的初始索引
int t = 0;//临时数组temp的初始索引
//1.比较左右序列当前元素的大小,将小的拷贝到temp中,并指针++,直到有一边序列处理完成
//while循环是为了让左右两边序列比较拷贝时一直执行
while(i <= mid && j<=right){
//左边序列当前元素小于右边序列当前元素,则将其拷贝到临时数组temp中
if (arr[i]<=arr[j]){
temp[t++] = arr[i++] ;
}else{
//否则是右边当前序列小于左边当前序列元素,则将小的拷贝到temp中
temp[t++] = arr[j++];
}
}
//2.将左右未排序完剩下的元素,依次添加到临时数组temp中,如4578 1236
while (i<=mid){//左边有剩余
temp[t++] = arr[i++];
}
while (j<=right){//左边有剩余
temp[t++] = arr[j++];
}
//3.临时数组中下标从0开始全部拷贝到arr数组中,因为递归调用会有多次拷贝,所以拷贝的temp数组长度也会变化
//第一次合并tempLeft=0,right=1/tempLeft=2 right=3/第二次合并tempLeft= 0 right = 3 最后一次是tempLeft= 0 right = 7
t=0;
int leftIndex = left;
System.out.println("leftIndex="+leftIndex+" right:"+right);
while(leftIndex<=right){
arr[leftIndex++] = temp[t++];
}
}
}