【Java学习笔记】归并排序的实现
参考了百度百科关于归并排序的论述。
归并排序不难理解,你需要知道:
- 一个只有一个数字的“数组”,是已经排好序的;
- 把两个已经排好序的数组,拼一块排序,其实是很简单、很迅速的;
- 任何长度的数组,都可以用很多的这个一个数字的“数组”两两拼接。
两两拼接的过程,就叫***归并***。
我们需要一个递归的方法来实现这个拼接过程:
//这个方法搭建了一个框架,实现了分治的思想。排序前数组为disorderArray,排序完成的数组为orderArray
public static void mergeSort(int[] disorderArray,int[] orderArray,int left,int right){
//中点索引位置
int mid = (left + right)/2;
//递归的条件:左右两边至少有2个元素,当只有1个元素时,必为有序”数组“。
if(mid > left){
mergeSort(disorderArray,orderArray,left,mid);
}
if((mid + 1) < right){
mergeSort(disorderArray,orderArray,mid+1,right);
}
//分割完毕,下层递归执行完毕,左右两边均为有序数组。
sort(disorderArray,orderArray,left,right);
}
我们还需要一个方法来实现把两个已经排好序的数组,拼一块排序的过程:
//这个方法是核心,排序前数组为disorderArray,排序完成的数组为orderArray。
//已知左右两边都是有序的,将两边的有序数组结合为统一有序的数组。
public static void sort(int[] disorderArray,int[] orderArray,int left,int right){
//中点索引位置
int mid = (left + right)/2;
//i,j分别为排序前数组的左右索引位置,k为排序后数组的索引位置
int i = left;
int j = mid + 1;
int k = left;
//判断i、j索引是否到边界。如果i到了边界,就把当前j索引以后的所有值填入。反之亦然
boolean iIsOut = false;
boolean jIsOut = false;
//循环结束条件:k值超过索引位置。
do{
//这里一共有四个判断:
//1.i索引出界了吗?如果出界了,那j剩下的所有值都填进去;
//2.j索引出界了吗?如果出界了,那i剩下的所有值都填进去;
//3.右半数组元素的小于左半数组元素?如果小,把右半放进去;
//4.剩下的情况就是右半数组元素的大于等于于左半数组元素了,把左半放进去。
if(iIsOut){
orderArray[k] = disorderArray[j];
//j,k索引位置向右移动,但j最右不能超过right索引。
k++;
if(j < right){
j++;
}else {
jIsOut = true;
}
}else if(jIsOut){
orderArray[k] = disorderArray[i];
//i,k索引位置向右移动,但i最右不能超过mid索引。
k++;
if(i < mid){
i++;
}else {
iIsOut = true;
}
}else if (disorderArray[i] > disorderArray[j]){
//当右半元素的小于左半元素的情况。
orderArray[k] = disorderArray[j];
//j,k索引位置向右移动,但j最右不能超过right索引。
k++;
if(j < right){
j++;
}else {
jIsOut = true;
}
}else {
//当左半元素的小于或者等于右半元素的情况,归并排序的稳定就在这里体现。
orderArray[k] = disorderArray[i];
//i,k索引位置向右移动,但i最右不能超过mid索引。
k++;
if(i < mid){
i++;
}else {
iIsOut = true;
}
}
}while (k < right + 1);
//将排好序的数组赋值给未排序的数组。
for (int l = left; l <= right; l++) {
disorderArray[l] = orderArray[l];
}
}
如此,你就完成了归并排序。20200623