刚开始接触归并排序的时候,感觉挺困难的,但是仔细的分析之后,就会发现它的原理还是蛮简单的:就是借助另外的一个数组空间将左右两侧(从中间mid处划分)已经排序好的原数组转到新的数组空间。如下图所示:
转移操作时,就是左右所指的数据进行比较,将较小的数据(由小到大排序)存储到新的数组空间。如下图所示:
了解了原理,剩下的就是将原来的无序数组转化为左右两侧为有序排列的数组,方法如下:
将无序数组一分为二,再将左侧和右侧两部分再次分别进行划分(即二分为四),以此类推,直到每组元素个数为一个或两个就可以进行比较,返回有序的数组,依次向上组合就可以得到左右有序的数组。
代码如下:
//归并排序
public class GuiBingPaiXu {
/*
* 主函数
*/
public static void main(String[] args) {
GuiBingPaiXu g=new GuiBingPaiXu();
int[] arrs={0,2,6,4,1,3,8,5,7};
arrs=g.sort(arrs);
for(int i:arrs){
System.out.print(i+",");
}
}
public int[] sort(int[] arrs){
if(arrs.length < 2){
return arrs; //只有一个元素,返回
}
int middle = arrs.length % 2 == 0 ? arrs.length / 2 : (arrs.length - 1) / 2; //取得中间位置
int[] left = Arrays.copyOfRange(arrs, 0, middle); //得到左侧数组
int[] right = Arrays.copyOfRange(arrs, middle, arrs.length); //得到右侧数组
int[] lres = sort(left); //递归对左侧进行分组(1分为2)
int[] rres = sort(right); //递归对右侧进行分组(1分为2)
return merge(lres, rres); //用左右比较的方法得到有序数组
}
private int[] merge(int[] lres, int[] rres) {
int[] res = new int[lres.length + rres.length]; //定义新数组
int l = 0; //左侧数组开始标记位
int r = 0; //右侧数组开始标记位
int c = 0; //新数组开始标记位
while(l < lres.length && r < rres.length){
if(lres[l] < rres[r]){ //左侧标记位数值小于右侧标记位数值
res[c++] = lres[l++]; //将左侧标记位数值复制到新数组,并将标记位++
} else {
res[c++] = rres[r++]; //将右侧标记位数值复制到新数组,并将标记位++
}
}
if(l == lres.length){ //左侧数组全部复制完毕后处理
while(r < rres.length){
res[c++] = rres[r++];
}
return res;
}
if(r == rres.length){ //右侧数组全部复制完毕后处理
while(l < lres.length){
res[c++] = lres[l++];
}
return res;
}
return res;
}
}