天下事,合久必分,分久必合。合并排序的基本思想正是先分再合。

例如对3, 1这个数列排序,首先是分,分为3和1两个数列,然后再合并并排序。合并需要额外的辅助空间,即建立一个两个数列长度之和的空数组用于存储合并结果。

合并分为三步:

1)两个数列在起始位置各分配一个"指针",对比指针位置的数字,取较小的数字存入辅助数组。数字被移出的一侧,指针右移一格,再次比较两个指针位置的数字,直到某一侧的指针移出数组以外结束。

2)把左侧数组剩余的数字按顺序移动到辅助数组中

3)把右侧数组剩余的数字按顺序移动到辅助数组中

过程如下图:

下面把两个数组的长度都增加到2,再看一下合并过程:

观察一下这个流程可以看出,这种合并排序的前提是左右两个数列本身是有序的。所以如果对4, 2,  3, 1排序,拆成4, 2和3, 1两个数列显然是不行的,需要继续拆分4, 2为4和2,然后合并为2, 4;拆分右侧为3, 1,然后合并成1, 3。最后合并2, 4和1, 3。

以4, 3, 6, 2, 7, 1, 5为例,完整的排序过程如下图:

来看代码:

  1. import java.util.Arrays;
  2. /**
  3. * 合并排序法
  4. * Created by autfish on 2016/9/20.
  5. */
  6. public class MergeSort {
  7. public static void main(String[] args) {
  8. int[] numbers = new int[] {4, 3, 6, 2, 7, 1, 5};
  9. System.out.println("排序前: " + Arrays.toString(numbers));
  10. MergeSort ms = new MergeSort();
  11. ms.sort(numbers, 0, numbers.length - 1);
  12. System.out.println("排序后: " + Arrays.toString(numbers));
  13. }
  14. public void sort(int[] numbers, int from, int to) {
  15. int middle = (from + to) / 2;
  16. if (from < to) {
  17. sort(numbers, from, middle);
  18. sort(numbers, middle + 1, to);
  19. //左侧数列最大值小于右侧数列最小值, 不需要通过合并来调整顺序
  20. if(numbers[middle] < numbers[middle + 1])
  21. return;
  22. merge(numbers, from, middle, to);
  23. }
  24. }
  25. private void merge(int[] numbers, int from, int middle, int to) {
  26. int[] temp = new int[to - from + 1];
  27. int left = from;
  28. int right = middle + 1;
  29. int i = 0;
  30. //从拆分到两边数列各剩一个数字开始合并; 当数列中有多个数字时, 一定是已经排好序的
  31. //从两边数列左侧开始依次取数对比, 挑选小的一个放入临时数组
  32. while (left <= middle && right <= to) {
  33. if (numbers[left] < numbers[right]) {
  34. temp[i++] = numbers[left++];
  35. } else {
  36. temp[i++] = numbers[right++];
  37. }
  38. }
  39. //把左边数列剩余的数移入数组
  40. while (left <= middle) {
  41. temp[i++] = numbers[left++];
  42. }
  43. //把右边数列剩余的数移入数组
  44. while (right <= to) {
  45. temp[i++] = numbers[right++];
  46. }
  47. System.arraycopy(temp, 0, numbers, from, temp.length);
  48. }
  49. }

运行:

  1. 排序前: [4, 3, 6, 2, 7, 1, 5]
  2. 排序后: [1, 2, 3, 4, 5, 6, 7]

合并排序平均情况和最坏情况的时间复杂度都是O(nlogn),因为需要额外的辅助空间,空间复杂度为O(n)。

Java与算法之(11) - 合并排序的更多相关文章

  1. 算法笔记_014:合并排序(Java)

    1 问题描述 给定一组数据,使用合并排序得到这组数据的非降序排列. 2 解决方案 2.1 合并排序原理简介 引用自百度百科: 合并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Div ...

  2. Java与算法之(10) - 希尔排序

    希尔排序是插入排序的一种,是直接插入排序的改进版本. 对于上节介绍的直接插入排序法,如果数据原来就已经按要求的顺序排列,则在排序过程中不需要进行数据移动操作,即可得到有序数列.但是,如果最初的数据是按 ...

  3. c++(合并排序)

    前面一篇博客提到的快速排序是排序算法中的一种经典算法.和快速排序一样,合并排序是另外一种经常使用的排序算法.那么合并排序算法有什么不同呢?关键之处就体现在这个合并上面.    合并算法的基本步骤如下所 ...

  4. java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述

    算法是在有限步骤内求解某一问题所使用的一组定义明确的规则.通俗点说,就是计算机解题的过程.在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法.前者是推理实现的算法,后者是操作实现的算法. ...

  5. 几种常见排序算法之Java实现(插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序)

    排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 稳定度(稳定性)一个排序算法是稳定的,就是当有两个相等记录的关 ...

  6. Shell排序算法和合并排序算法

    Shell排序(希尔排序)算法Shell排序严格来说基于插入排序的思想,其又称为希尔排序或者缩小增量排序. Shell排序的流程:1.将由n个元素的数组分成n/2个数字序列,第1个数据和第n/2+1个 ...

  7. java讲讲几种常见的排序算法(二)

    java讲讲几种常见的排序算法(二) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 堆排序 思路:构建一个小顶堆,小顶堆就是棵二叉树,他的左右孩子均大于他的根节点( ...

  8. 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...

  9. 数据结构和算法 – 11.高级排序算法(上)

      对现实中的排序问题,算法有七把利剑可以助你马道成功. 首先排序分为四种:       交换排序: 包括冒泡排序,快速排序.       选择排序: 包括直接选择排序,堆排序.       插入排序 ...

随机推荐

  1. C# 接口使用方法

    之前一直不理解接口这一概念,今天无意中翻书,网上查资料悟道其中的道理,现在工作没有用到interface这一块,怕以后会遇到忘记实现的方法便记录下来,哪里写的不对希望读者指出,话不多说,接下来看我对接 ...

  2. 历史命令~/.bash_history,查看所有别名alias,命令执行顺序,命令行常用快捷键,输入输出重定向,wc统计字节单词行数

    历史命令大小:/etc/profile中字段HISTSIZE=1000 历史命令保存文件:~/.bash_history history -c 清空历史命令 history -w 把历史命令写入~/. ...

  3. 多表连接时USING和ON的区别,USING会去掉重复列,ON显示重复列。

  4. [LeetCode] 动态规划入门题目

    最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手. 首先,动态规划是什么呢?很多人认为把它称作一种"算法" ...

  5. Solr集群搭建详细教程(二)

    注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com. 之前步骤:Solr集群搭建详细教程(一) 三.solr集群搭建 注意 ...

  6. Python 爬虫实战(一):使用 requests 和 BeautifulSoup

    Python 基础 我之前写的<Python 3 极简教程.pdf>,适合有点编程基础的快速入门,通过该系列文章学习,能够独立完成接口的编写,写写小东西没问题. requests requ ...

  7. scrollTop的兼容性

    各浏览器下 scrollTop的差异 IE6/7/8: 对于没有doctype声明的页面里可以使用 document.body.scrollTop 来获取 scrollTop高度 : 对于有docty ...

  8. pstree 命令详解

    作用: 以命令树状图的方式展现进程之间的派生关系, 显示效果比较直观. 选项: -a 显示每个程序的完整指令, 包含路径, 参数或者是常驻服务的标志 -c 不使用精简标示法 -h 列出树状图,特别标明 ...

  9. Mobiscroll的介绍【一款兼容PC和移动设备的滑动插件】

    Mobiscroll是一个用于触摸设备的日期和时间选择器,它的使用不会改变HTML5.PhoneGap以及混合应用的原生用户体验.作为一款jQuery滑动选择插件,用户可以自定义主题样式,为自己的移动 ...

  10. 不解释,分享这个base.css

    @charset "utf-8"; /*! * @名称:base.css * @功能:1.重设浏览器默认样式 * 2.设置通用原子类 */ /* 防止用户自定义背景颜色对网页的影响 ...