归并排序法 - Merge Sort

简单记录 - 玩转算法系列–玩转算法 -高级排序算法(Sorting-Advance)

O(n*log n)的排序算法 归并排序法 - Merge Sort

nlogn 比 n^2 快多少?



测试用例太少了 优势 数据量

nlogn 的算法,n逐渐增大,速度优势越来越明显。

一个优化改进后的算法也许是一个笨的算法一辈子都赶不上的结果,好的优化后算法一瞬间就运算完了。

归并排序设计思想

归并排序算法会把序列分成长度相同的两个子序列,当无法继续往下分时(也就是每个子序列中只有一个数据时),就对子序列进行归并。归并指的是把两个排好序的子序列合并成一个有序序列。该操作会一直重复执行,直到所有子序列都归并为一个整体为止。

时间、空间复杂度

归并排序

执行时间:平均情况与最差情况为O(nlog(n)),

归并排序中,分割序列所花费的时间不算在运行时间内(可以当作序列本来就是分割好的)。在合并两个已排好序的子序列时,只需重复比较首位数据的大小,然后移动较小的数据,因此只需花费和两个子序列的长度相应的运行时间。也就是说,完成一行归并所需的运行时间取决于这一行的数据量。看一下上面的图便能得知,无论哪一行都是n个数据,所以每行的运行时间都为O(n)。而将长度为n的序列对半分割直到只有一个数据为止时,可以分成log2n行,因此,总共有log2n行。也就是说,总的运行时间为O(nlogn)。

存储空间:看情况。一般是归并排序的空间复杂度是O(n),因为归并时用到了辅助数组。

归并排序是将数组分成两半,这两半分别排序后,再归并在一起。排序某一半时,继续沿用同样的排序算法,最终,将归并两个只含一个元素的数组。这个算法的重点在于“归并”。

快速排序

执行时间:平均情况为O(nlog(n)),最差情况为O(n2),

存储空间:O(log(n))快速排序指随机挑选一个元素,对数组进行分割,以将所有比它小的元素排在比它大的元素前面。

快速排序在一般情况下,一致认为快速排序是最好的一种排序算法,而且不需要额外的存储空间。其最佳应用场合是应用于大型数据集。

我们知道归并排序的时间复杂度是O(nlogn),比最直观的O(n2)要快,但同时归并排序需要一个长度为n的辅助数组,相当于我们用O(n)的空间消耗换来了时间效率的提升,因此这是一种用空间换时间的算法。尽管归并排序可以使用手摇算法将额外空间复杂度降至 O(1),但这样最差情况下的时间复杂度会因此上升至O(N2)。

归并排序基本上与快速排序算法的性能相同,但它需要使用两倍于快速排序的存储空间,而具有讽刺意味的是,其最佳应用场合是在超大数据集中,因为归并排序的原理就是对原始的乱序数据不断进行对半分割。

归并排序图解

Merge Sort

归并排序

归并基本思想是将两个(或以上)有序的序列合并成一个新的有序序列。细化来说,归并排序先将长度为n的无序序列看成是n个长度为1的有序子序列,首先做两两合并,得到 n/2个长度为2的有序子序列,再做两两合并……不断地重复这个过程,最终可以得到一个长度为n的有序序列。

整个序列一直划分,直到无法继续往下分时(也就是每个子序列中只有一个数据时),就对子序列进行归并。

O(n*log n)

O(n) O(logn)

每一部分就一个元素了 。为什么分到只有一个呢?不用排序了 ,简单归并。

例如:长度为8的数据序列,只需经过3次合并。也就是说,对于长度为n的数据序列,只需经过log2n次合并。对于归并排序而言,其算法关键就在“合并”。如何将两个有序的数据序列合并成一个新的有序序列?合并算法的具体步骤如下。

左右分别排序 分半 排序 归并

8 6 2 3 1 5 7 4

6 8 2 3 1 5 4 7

归并过程Merge



辅助我们 临时空间 存储序列

多使用了存储空间 O(n)

时间、空间 一般优先考虑时间

三个索引 i j k

最后序列 1 2 3 4 5 6 7 8

归并过程 一部分与另一部分比较 一个个比 小到大 小就放过去

递归 归并排序

归并排序描述

像快速排序算法一样,由于归并排序也是一种分治算法,因此可以用分治法的思想将排序分为三个步骤,这样有助理解:

1.分:将数据集等分为两半。

2.治:分别在两个部分用递归的方式继续使用归并排序法。

3.合:将分开的两个部分合并成一个有序的数据集。

归并排序与其他排序最大的不同在于它的归并过程。这个过程就是将两个有序的数据集合并成一个有序的数据集。正如我们看到的,合并两个有序数据集的过程是高效的,因为我们只需要遍历一次即可。根据以上事实,再加上该算法是按照可预期的方式来划分数据的,这使得归并排序在所有的情况下都能达到快速排序的平均性能。遗憾的是,归并排序需要额外的存储空间来运行,这也是它的一个缺点。因为合并过程不能在无序数据集本身中进行,所以必须要有两倍于无序数据集的空间来运行算法。这点不足极大地降低实际中使用归并排序的频率,因为通常可以使用不需要额外存储空间的快速排序来代替它。然而,归并排序对于海量数据处理还是非常有价值的,因为它能够按预期将数据集分开。这使得我们能够将数据集分割为更加可管理的数据,接着用归并排序将处理数据,然后不断地合并数据,在这个过程中并不需要一次存储所有的数据。

归并排序小结

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。归并排序算法会把序列分成长度相同的两个子序列,当无法继续往下分时(也就是每个子序列中只有一个数据时),就对子序列进行归并。归并指的是把两个排好序的子序列合并成一个有序序列。该操作会一直重复执行,直到所有子序列都归并为一个整体为止。

归并排序执行时间:平均情况与最差情况为O(nlog(n)),存储空间:看情况。一般是归并排序的空间复杂度是O(n),因为归并时用到了辅助数组。

快速排序在一般情况下,一致认为快速排序是最好的一种排序算法,而且不需要额外的存储空间。归并排序与快速排序一样,它依赖于元素之间的比较来排序,归并排序在所有的情况下都能达到快速排序的平均性能。但是,归并排序需要额外的存储空间来完成排序过程。

参考资料

1、算法精解:C语言描述作者:【美】劳顿(Loudon,K.)

2、我的第一本算法书作者:[日]宫崎修一,石田保辉

3、玩转算法系列–玩转算法 -高级排序算法

【高级排序算法】1、归并排序法 - Merge Sort的更多相关文章

  1. 【DS】排序算法之归并排序(Merge Sort)

    一.算法思想 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法的一个非常典型的应用,指的是将两个已经排序的序列合并成一个序列的操作.其归并思想如下: 1)申请空间,使其大小为两个已经 ...

  2. 排序算法:归并排序(Merge Sort)

    归并排序 归并排序采用了分治策略(divide-and-conquer),就是将原问题分解为一些规模较小的相似子问题,然后递归解决这些子问题,最后合并其结果作为原问题的解. 归并排序将排序数组A[1. ...

  3. javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法)

    javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法) 一.快速排序算法 /* * 这个函数首先检查数组的长度是否为0.如果是,那么这个数组就不需要任何排序,函数直接返回. * ...

  4. 【算法】归并排序(Merge Sort)(五)

    归并排序(Merge Sort) 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序 ...

  5. 【高级排序算法】2、归并排序法的实现-Merge Sort

    简单记录 - bobo老师的玩转算法系列–玩转算法 -高级排序算法 Merge Sort 归并排序 Java实现归并排序 SortTestHelper 排序测试辅助类 package algo; im ...

  6. [算法]——归并排序(Merge Sort)

    归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlog ...

  7. Java常见排序算法之归并排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  8. javascript数据结构与算法--高级排序算法

    javascript数据结构与算法--高级排序算法 高级排序算法是处理大型数据集的最高效排序算法,它是处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个.现在我们来学习下2种高级排序算法-- ...

  9. javascript高级排序算法之快速排序(快排)

    javascript高级排序算法之快速排序(快排)我们之前讨论了javascript基本排序算法 冒泡排序 选择排序 插入排序 简单复习: 冒泡排序: 比较相邻的两个元素,如果前一个比后一个大,则交换 ...

随机推荐

  1. SpringBoot集成基于tobato的fastdfs-client实现文件上传下载和删除

    1. 简介   基于tobato的fastdfs-client是一个功能完善的FastDFS客户端工具,它是在FastDFS作者YuQing发布的客户端基础上进行了大量的重构,提供了上传.下载.删除. ...

  2. 【涂鸦物联网足迹】用煲仔饭来说明IaaS/PaaS/SaaS的区别

    最近在准备一些科普性的知识内容,发现大家对于一些基础性的知识概念还是有点模糊.今天先来简单介绍一下IaaS/PaaS/SaaS的区别~ 其实还有一个On-Premises(本地部署)的概念,也可以一并 ...

  3. js下 Day05、DOM案例

    一.简易购物车 效果图: 功能思路分析: 功能一:数量加减 \1. 找到所有的加号按钮,循环绑定点击事件.点击加号时让对应的数量+1 (找清楚加号和数量的关系,让数量标签的内容++) \2. 找到所有 ...

  4. eclipse 创建自己的Maven项目(超详细)

    本文章 主要是 讲解 是讲解 eclipse创建项目 --SpiritMark_liu 先配置 Maven 的 settings 地址 (Window -> Perferences–>Ma ...

  5. JS C# 正则表达式去除html字符中所有的标签(img em标签除外)

    js去除em标签 $(this).html().replace(/<(?!em|\/em).*?>/g, '') C#去除 System.Text.RegularExpressions.R ...

  6. ubuntu20部署php-swoole开发环境

    第1步:安装依赖 add-apt-repository ppa:ondrej/php apt install php-dev 第2步:编译安卓swoole wget https://codeload. ...

  7. Kibana查询语言(KQL)

    一.前言 现在大多数的公司都会使用ELK组合来对日志数据的收集.存储和提供查询服务,这里就不介绍什么是ELK了,只介绍一些EKL中的查询,也就是K(kibana). 查询数据库,如果是MySQL,那么 ...

  8. idea修改项目名导致无法找到主类

    描述 本地创建项目copy或者是修改项目名和文件夹名称后 启动springboot项目失败 控制台报错 错误无法找到主类 解决办法 1. 求助互联网得知 需要执行 mvn clean install( ...

  9. DRF视图的使用及源码流程分析

    django rest framework中对于APIView.GenericAPIView.ModelViewSet.mixins扩展类的分析. APIView 示例 根据实际程序来分析: urls ...

  10. 关于ajax已经成功了,却报404的错误的问题

    经分析是请求没有返回状态码,这是因为我用的是SpringMVC框架,前后端使用JSON传递数据,因为返回的是对象,而忘记了添加 @ResponseBody 注解,所以 Spring对我的返回值进行了映 ...