归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。这是百度百科给的解释,需要深入体会。。。记住最后一句话,归并排序是一种稳定的排序方法。

下面说下其他版本的解释:归并排序可以看做是一场比武大会,比武大会需要选拔出最厉害的武术高手,可是参与者众多,总不能让他们去打群架吧?所以擂台赛这样的比武方式出现了。无论参赛者有多少人,主办方都可以让他们两两比试,第一轮的胜者再分成两两一组,继续比试。。。一直到决出冠军为止。

举个例子,有A、B、C、D、E、F、G、H一共8个武术家参考参加比武大会。

第一轮,两两一组,有4名选手胜出(四分之一决赛)

第二轮,两两一组,有两名选手胜出(半决赛)

第三轮,仅剩的两人一组,冠军胜出(总决赛)

这就是擂台赛的流程:先进行两两分组比赛,小组胜出者继续分组比赛,最终选出第一名。归并排序的流程也是类似,但又存在一些不同之处。

归并排序和擂台赛,有什么相同和不同之处呢?让我们以下面这个数组来举例说明:

归并排序就像是组织一场元素之间的“比武大会”,这场比武大会分成两个阶段:

1.分组

假设集合一共有n个元素,算法将会对集合进行逐层的折半分组。

第一层分成两个大组,每组n/2个元素;

第二层分成4个小组,每组n/4个元素;

第三层分成8个更小的组,每组n/8个元素;

......

一直到每组只有一个元素为止。

这样一来,整个数组就分成了一个个小小的“擂台”。

2.归并

既然分了组,接下来就要开始“比武”了。

归并排序和擂台赛有一个很大的不同,就是擂台赛只需要决定谁是老大,而并不关心谁做老二和老三;归并排序的要求复杂一些,需要确定每一个元素的排列位置。

因此,当每个小组内部比较出先后顺序以后,小组之间会展开进一步的比较和排序,合并成一个大组;大组之间继续比较和排序,再合并成更大的组......最终,所有元素合并成了一个有序的集合。

这个比较与合并的过程叫做归并,对应英文单词merge,这正是归并排序名字的由来。

归并操作需要哪三个步骤呢?我们以两个长度为4的集合为例:

第一步,创建一个额外大集合用于存储归并结果,长度是两个小集合之和。(p1,p2,p是三个辅助指针,用于记录当前操作的位置)

第二步,从左到右逐一比较两个小集合中的元素,把较小的元素优先放入大集合。

由于1<2,所以把元素1放入大集合,p1和p各右移一位:

由于2<3,所以把元素2放入大集合,p2和p各右移一位:

由于3<7,所以把元素3放入大集合,p1和p各右移一位:

由于5<7,所以把元素5放入大集合,p1和p各右移一位:

由于6<7,所以把元素6放入大集合,p1和p各右移一位:

此时左侧的小集合已经没有元素可用了。

第三步,从另一个还有剩余元素的集合中,把剩余元素按顺序复制到大集合尾部。

这样一来,两个有序的小集合就归并成了一个有序的大集合。

下面看看具体实现代码:

package com.lzy.sort;/*** @Auther: 安静读书* @Date: 2019/10/12 06:30* @Description:归并排序算法*/
public class MergeSort {public static int [] mergeSort(int[] nums,int l, int h){if(l == h)return new int[] {nums[l]};int mid = l + (h - l)/2;int[] leftArr = mergeSort(nums, l , mid);//左有序数组int[] rightArr = mergeSort(nums, mid + 1, h);//右有序数组int[] newNum = new int[leftArr.length + rightArr.length];//新有序数组int m = 0, i = 0, j = 0;while (i < leftArr.length && j < rightArr.length){newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];}while (i < leftArr.length)newNum[m++] = leftArr[i++];while (j < rightArr.length)newNum[m++] = rightArr[j++];return newNum;}public static void main(String[] args) {int nums[] = new int[]{1,2,5,9,6,4,7,10,8,9};int newNums[] = mergeSort(nums,0,nums.length - 1);for(int x : newNums){System.out.println(x);}}
}

最后说说归并排序的时间复杂度和空间复杂度:

归并排序把集合一层一层进行拆半分组。如果集合长度是n,那么拆半的层数就是logn,每一层进行归并操作的运算量是n。

所以归并排序的时间复杂度是每一层的运算量乘以层级数,即O(n log n) 。

由于每次归并所创建的额外集合都会随着方法的结束而被释放,因此这部分空间不应该累加计算,单词归并操作开辟的最大空间是n,所以归并排序的空间复杂度是T(n)。

归并排序是稳定的排序方式,两个值相同的元素在归并之后,左侧的元素仍然在左,右侧的元素仍然在右。

Come on!!!

每天一排序:归并排序相关推荐

  1. 第十章-排序-归并排序与基数排序

    2-1 对N个记录进行归并排序,归并趟数的数量级是: (1分) O(logN) O(N) O(NlogN) O(N​2​​) 2-2 对N个记录进行归并排序,空间复杂度为: (1分) O(logN) ...

  2. 外部排序归并排序 败者树

    一.定义问题 外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的.外部排序最常用的算法是多路 ...

  3. 大话算法-排序-归并排序

    归并排序是将两个已经排序的序列合并成一个序列的操作 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 2.设定两个指针,最初位置分别为两个已经排序序列的起始位置 3.比较两个指 ...

  4. 【排序】归并类排序—归并排序(逆序数问题)

    文章目录 前言 归并排序(merge sort) 逆序数 结语 微信公众号:bigsai 数据结构与算法专栏 前言 在排序中,我们可能大部分更熟悉冒泡排序.快排之类.对归并排序可能比较陌生.然而事实上 ...

  5. AcWing - 113 特殊排序(归并排序/二分)

    题目链接:点击查看 题目大意:现在给出n*(n-1)/2个关系表示n个数中两两之间的关系大小,用函数表示就是compare(a,b),若a<b,则返回值为true,否则返回值为false,要求我 ...

  6. 看动画学算法之:排序-归并排序

    文章目录 简介 归并排序的例子 归并排序算法思想 归并排序的java实现 归并排序的时间复杂度 简介 归并排序简称Merge sort是一种递归思想的排序算法.这个算法的思路就是将要排序的数组分成很多 ...

  7. 算法-排序-归并排序

    归并排序 特点:非原址排序,比较排序,时间复杂度O(nlgn) 稳定 // // Created by 许加权 on 2021/6/18. //#include <iostream> vo ...

  8. 理论基础 —— 排序 —— 归并排序

    [概述] 归并排序是一种稳定的排序方法,其是分治策略的一个非常典型的应用. 其基本思想是:将 n 个待排序的记录看成是 n 个长度为 1 的有序序列,然后两两进行归并,第一轮得到 [n/2] 个长度为 ...

  9. 排序——归并排序和快速排序

    1,归并排序的基本思想: 1,将两个或两个以上的有序序列合并成一个新的有序序列,比如有序序列 v[0] ... v[m] 和 v[m+1] ... v[n-1] 合并为 v[0] ... v[n-1] ...

  10. 排序:归并排序(C)

    文章目录 1.思想 1.1 思想流程图 1.2 思路解释 2.算法执行过程 3.算法实现 3.1 方法定义 3.2 方法实现 3.3 方法调用 4.复杂度 1.思想 1.1 思想流程图 1.2 思路解 ...

最新文章

  1. PS怎么将自己的形状存储为自定形状?
  2. python3读取excel数据-python3读取Excel表格数据的代码分享
  3. kibana操作elasticsearch:新增数据(随机生成id)
  4. python 文本相似度计算函数_四种计算文本相似度的方法对比
  5. Nature封面:大团队日趋中庸,小团队更容易出颠覆性创新
  6. zbrush缝线笔刷制作_Thepoly | 高质量写实人脸制作及实时渲染分享
  7. fanuc服务器显示6,FANUC常用系统参数说明 (6页)-原创力文档
  8. 三大主流芯片架构特点
  9. SpringCloud原理分析
  10. 马云马总,我祝福您全家和以后的子子孙孙都有996福报
  11. html5分镜头脚本范例,分镜头脚本模板(小故事分镜头脚本范例)
  12. linux将两个目录做软连接,centos软连接创建
  13. C++:设计模式之命令模式(例子)
  14. ADP(自适应动态规划)-扩展HDP
  15. 又又又一边缘计算初创企业融资
  16. 当a=1,b=2,c=3时,if(ac)b=a;a=c;c=b;的执行结果详解
  17. SQL中的笛卡尔你真的懂吗?
  18. GraphQL的认识与使用
  19. 神经网络和深度神经网络,图神经网络和神经网络
  20. 03-docker系列-docker容器的基本操作

热门文章

  1. 《看聊天记录都学不会C语言?太菜了吧》(21)(必懂!题解)在现实生活中,打擂台比赛争名次竟用的是冒泡排序?
  2. Android 的触摸反馈以及事件分发机制
  3. 大数据技术助推数字化智慧城市管理平台的搭建
  4. android 滴滴司机接单滑动按钮,笔记20171127-Android仿滴滴呼叫车时转圈圈的View
  5. Linux的系统管理命令和压缩命令和编辑器
  6. 基于java+springboot+mybatis+vue+elementui的健身房课程预约管理系统
  7. SQL截取字符串中的某个特定位置部分
  8. Ableton Live 10 Suite功能特色
  9. 三个数的排序常用方法
  10. itools苹果录屏大师_苹果怎么录屏?这两种方法值得了解