经典算法之归并排序

归并逻辑

归并是采用分治和递归的思想完成的,主要是将数组分成多个小数组,保证小数组内数字有序。
例如:

1, 0, 4, 3, 7, 10, 5, 9
分治之后会形成 1,0,4,3,7,10,5,9 八个只含有一个数字的数组,并保证每一个子数组有序
然后进行合并 1,0, 形成 0,1然后4,3,形成 3,4, 依次类推 最后形成 单个有序子数组
再将数组合并 递归调用 最后形成完整有序数组

代码实现

 //定义一个数组用于存储中间过程数据
    int[] tmp;

    public int[] sortArray(int[] nums) {
        // 初始化中间数组
        tmp = new int[nums.length];
        mergeSort(nums, 0, nums.length - 1);
        return nums;

    }

    private void mergeSort(int[] nums, int l, int r) {
        if (l >= r) return;
        int mid = (l + r) >> 1;
        // 因为排序要对所有元素 索引 包含mid
        mergeSort(nums, l, mid);
        mergeSort(nums, mid + 1, r);
        // 因为mid 为左数组临界 索引j不能包含mid
        int i = l, j = mid + 1;
        int cnt = 0;
        // 进行分治 mid 为左数组临界 r为右数组临界 l,mid + 1 分别为左右数组开始临界
        while (i <= mid && j <= r) {
            if (nums[i] <= nums[j]) {
                tmp[cnt++] = nums[i++];
            } else {
                tmp[cnt++] = nums[j++];
            }
        }
        while (i <= mid) {
            tmp[cnt++] = nums[i++];
        }
        while (j <= r) {
            tmp[cnt++] = nums[j++];
        }
        for (int k = 0; k < r - l + 1; k++) {
            nums[k + l] = tmp[k];
        }
    }

讲解:
定义 mergeSort(nums, l, r) 函数表示对 nums 数组里 [l,r] 的部分进行排序,整个函数流程如下:
1. 递归调用函数 mergeSort(nums, l, mid) 对 nums 数组里 [l,mid] 部分进行排序。
2. 递归调用函数 mergeSort(nums, mid + 1, r) 对 nums 数组里 [mid+1,r] 部分进行排序。
3. 此时 nums 数组里 [l,mid] 和 [mid+1,r] 两个区间已经有序,我们对两个有序区间线性归并即可使 nums 数组里 [l,r] 的部分有序。
4. 线性归并的过程并不难理解,由于两个区间均有序,所以我们维护两个指针 i 和 j 表示当前考虑到 [l,mid] 里的第 i 个位置和 [mid+1,r] 的第 j 个位置。

如果 nums[i] <= nums[j] ,那么我们就将 nums[i] 放入临时数组 tmp 中并让 i += 1 ,即指针往后移。否则我们就将 nums[j] 放入临时数组 tmp 中并让 j += 1 。
如果有一个指针已经移到了区间的末尾,那么就把另一个区间里的数按顺序加入 tmp 数组中即可。
这样能保证我们每次都是让两个区间中较小的数加入临时数组里,那么整个归并过程结束后 [l,r] 即为有序的。

posted @ 2022-08-17 11:40  SpoonBlog  阅读(30)  评论(0)    收藏  举报