归并排序

归并排序

基本思想

归并排序其实是分治思想的体现,先解决小规模的问题,小规模的问题解决后,大的问题自然就会得到解决。

例如对于长度为15的数组a,先将子数组a[0-7]排序,再将a[8-14]排序,这两个子数组排序后归并结果即可。整个过程其实可以用一个二叉树来表示:

这里写图片描述

图1 归并排序示意图

归并两个已经排序的子数组的过程中,需要将这两个子数组的值复制到另一个临时数组中,再从小到大归并到原数组。

代码实现

代码实现如下:

/**
 * <p>文件描述: 归并排序</p>
 *
 * @Author luanmousheng
 * @Date 17/8/1 下午2:46
*/
public class MergeSort {

    //归并时用到的临时空间
    private static int[] temp;

    public static void sort(int[] arr) {
        if (arr == null) {
            return;
        }
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(int[] arr, int lo, int hi) {
        //如果数组开始位置大于等于结束位置,说明本次排序完成,返回
       if (lo >= hi) {
           return;
       }
       //取中间位置
       int mid = (lo + hi) /2;
       //将左边的部分排序
       sort(arr, lo, mid);
       //将右边的部分排序
       sort(arr, mid+1, hi);
       //此时两边已经是排序的,归并结果
       merge(arr, lo, mid, hi);
    }

    private static void merge(int[] arr, int lo, int mid, int hi) {
        //先将原数组lo到hi处的值复制到临时数组
        for (int i = lo; i <= hi; i++) {
            temp[i] = arr[i];
        }
        //i是左边数组的开始位置
        int i = lo;
        //j是右边数组的开始位置
        int j = mid+1;
        //遍历原数组lo到hi位置,
        for (int k = lo; k <= hi; k++) {
            if (i > mid) {
                //左边部分已经遍历完
                arr[k] = temp[j++];
            } else if (j > hi) {
                //右边部分已经遍历完
                arr[k] = temp[i++];
            } else if (temp[i] < temp[j]) {
                //取较小的值放到原来数组的位置k处
                arr[k] = temp[i++];
            } else {
                arr[k] = temp[j++];
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {4,3,5,8,11,9,2,7};
        temp = new int[arr.length];
        sort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ", ");
        }
    }

}

这里的逻辑就是先递归排序左边的数组,然后递归排序右边的数组,接着归并这两个已经排序完成的数组。

这里写图片描述

图2 两个有序数组的归并

图2 归并时会将原数组的数据复制到临时数组,临时数组上放上两个指针i和j,分别指向左边数组和右边数组的开始位置,比较这两个位置的值并将较小的值存储到原数组,直到这两个子数组遍历完成。

复杂度

归并排序的空间复杂度为O(n),时间复杂度为O(nlogn)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值