归并排序算法 java实现

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;
    }

}
posted @   H的世界  阅读(5)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示