public static void main(String[] args) {
int[] arr = {9, 5, 7, 3, 1, 6, 8, 4, 2};
mergeSort(arr,0,arr.length - 1);
}
/**
* 归并排序
* 注意:归并的拆分数组和合并数组是从左到右依次进行的,网上很多文章都是错误的
* 并不是左右一起拆分,网上很多文章都是这样的拆分图,其实是不对的
* 9,5,7,3,1,6,8,4,2
* 9,5,7,3,1 6,8,4,2 第一次拆分
* 9,5,7 3,1 6,8 4,2 第二次拆分
* 而是
* 9,5,7,3,1,6,8,4,2
* 9,5,7,3,1 6,8,4,2 第一次拆分,右边数组不动,因为一直在递归的是左边数组中的
* 9,5,7 3,1 6,8,4,2 第二次拆分,右边数组不动,因为一直在递归的是左边数组中,此时左边数组又拆分成2个数组
* 9,5 7 3,1 6,8,4,2 第三次拆分,右边数组还不动,因为一直在递归的是左边数组中的,左边再拆分至单个元素,单个元素我们认为就是有序
* 5,9 7 3,1 6,8,4,2 开始合并第三次拆分的数组
* 5,7,9 3,1 6,8,4,2 开始拆3,1的数组,再拆的话就是单个元素了
* 5,7,9 3 1 6,8,4,2 拆完左右都是单个元素
* 5,7,9 1,3 6,8,4,2 单个元素认为是有序的,所以合并成一个有序数组
* 5,7,9,1,3 6,8,4,2 合并第二次拆分的数组
* 1,3,5,7,9 6,8,4,2 至此,第一次拆分的左边的数组已经排好序,下面开始拆分右边的数据
* 1,3,5,7,9 6,8 4,2 此时才拆分右边的数据,重复上面步骤
* @param arr
* @param left
* @param right
*/
private static void mergeSort(int[] arr, int left, int right) {
//表示递归的限定条件,如果左边界和右边界相等,说明已经拆分到最小单元的元素了,直接返回开始合并
if (left >= right) {
return;
}
int mid = left + (right - left) / 2;
mergeSort(arr,left,mid); //对于左边数组来说,mid就是右边界
mergeSort(arr,mid + 1,right); //对于右边数组来说,mid + 1就是左边界
merge(arr,left,mid,right);//开始合并,左边的数组(第一次拆分的数组)合并完成,才会拆分和合并右边(第一次拆分)的数组
System.out.println(Arrays.toString(arr));
}
private static void merge(int[] arr, int left, int mid, int right) {
//临时数组用来存储合并之后的有序元素
int[] temp = new int[right -left + 1];
//左数组的初始下标
int i = left;
//右数组的初始下标,mid同时也是左边数组的右边界
int j = mid + 1;
//临时数组的初始下标
int k = 0;
//左右两个数组开始比较,合并到临时数组中
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
//左边数组的下标移动,右边数组下标不动
temp[k++] = arr[i++];
} else {
//右边数组的下标移动,左边数组下标不动
temp[k++] = arr[j++];
}
}
//说明左边数组还有剩余的元素,直接全部放入temp数组中,因为多余的肯定是排好序的而且都是比当前temp中元素大的值
while (i <= mid) {
temp[k++] = arr[i++];
}
//说明右边数组还有剩余的元素,直接全部放入temp数组中,因为多余的肯定是排好序的而且都是比当前temp中元素大的值
while (j <= right) {
temp[k++] = arr[j++];
}
//已经排好序的临时数组,要复制到原数组中,下标肯定是从left开始
for (int t : temp) {
arr[left++] = t;
}
}
标签:归并,java,数组,int,arr,mid,拆分,排序,left
From: https://www.cnblogs.com/Houqz/p/18086044