面试常考算法——归并算法

归并排序(Merge Sort)

基本思想

核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并。归并排序将分治的思想体现得淋漓尽致。

代码实例

package com.yq.javaSEPrj.algorithm;


import java.util.Arrays;

public class MergeSort {
    /**
     * 主题函数
     */
     public static void sort(int[] A, int lo, int hi) {
        // 判断是否只剩下最后一个元素
        if (lo >= hi) return;

        // 从中间将数组分成两个部分
        int mid = lo + (hi - lo) / 2;

        // 分别递归地将左右两半排好序
        sort(A, lo, mid);
        sort(A, mid + 1, hi);

        // 将排好序的左右两半合并
        merge(A, lo, mid, hi);
        System.out.println(Arrays.toString(A));
    }

    /**
     * 归并操作
     */
     public static void merge(int[] nums, int lo, int mid, int hi) {
        // 复制一份原来的数组
        int[] copy = nums.clone();

        // 定义一个 k 指针表示从什么位置开始修改原来的数组,i 指针表示左半边的起始位置,j 表示右半边的起始位置
        int k = lo, i = lo, j = mid + 1;

        while (k <= hi) {
            if (i > mid) {
                nums[k++] = copy[j++];
            } else if (j > hi) {
                nums[k++] = copy[i++];
            } else if (copy[j] < copy[i]) {
                nums[k++] = copy[j++];
            } else {
                nums[k++] = copy[i++];
            }
        }
    }

    // 测试
    public static void main(String[] args) {
        int[] arr =  {2, 1, 7, 9, 5, 8};
        sort(arr,0,arr.length -1 );
    }
}

实现

一开始先把数组从中间划分成两个子数组,一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素,才开始排序。
排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。

其中,While 语句比较,一共可能会出现四种情况。
  • 左半边的数都处理完毕,只剩下右半边的数,只需要将右半边的数逐个拷贝过去。

  • 右半边的数都处理完毕,只剩下左半边的数,只需要将左半边的数逐个拷贝过去就好。

  • 右边的数小于左边的数,将右边的数拷贝到合适的位置,j 指针往前移动一位。

  • 左边的数小于右边的数,将左边的数拷贝到合适的位置,i 指针往前移动一位。

例题分析

例题:利用归并排序算法对数组 [2, 1, 7, 9, 5, 8] 进行排序。

解题思路
首先不断地对数组进行切分,直到各个子数组里只包含一个元素。
接下来递归地按照大小顺序合并切分开的子数组,递归的顺序和二叉树里的前向遍历类似。

  1. 合并 [2] 和 [1] 为 [1, 2]。
  2. 子数组 [1, 2] 和 [7] 合并。
  3. 右边,合并 [9] 和 [5]。
  4. 然后合并 [5, 9] 和 [8]。
  5. 最后合并 [1, 2, 7] 和 [5, 8, 9] 成 [1, 2, 5, 8, 9],就可以把整个数组排好序了。
  6. 合并数组 [1, 2, 7] 和 [5, 8, 9] 的操作步骤如下。

把数组 [1, 2, 7] 用 L 表示,[5, 8, 9] 用 R 表示。 合并的时候,开辟分配一个新数组 T
保存结果,数组大小应该是两个子数组长度的总和 然后下标 i、j、k 分别指向每个数组的起始点。 接下来,比较下标i和j所指向的元素 L[i]
和 R[j],按照大小顺序放入到下标 k 指向的地方,1 小于 5。 移动 i 和 k,继续比较 L[i] 和 R[j],2 比 5 小。
i 和 k 继续往前移动,5 比 7 小。 移动 j 和 k,继续比较 L[i] 和 R[j],7 比 8 小。
这时候,左边的数组已经处理完毕,直接将右边数组剩余的元素放到结果数组里就好。 合并之所以能成功,先决条件必须是两个子数组都已经分别排好序了。

收录自谷歌大佬

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李鑫海。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值