Motivate
MergeSort是个相对古老的算法了,为什么现在我们还要讨论这么古老的东西呢?有几个原因:
  • 它虽然年龄很大了,但是在实践中一直被沿用,仍然是很多程序库中的标准算法之一。
  • 实现它的本质是分治思想,是一个理解分治算法思想的好例子,好起点。
  • 本文会使用“递归树”来对它进行运行时间分析,后面会集合这种思路生成“主方法”。
题目
 
输入一个数组,数组里面的每个数字是不重复的,输出是已经排序好的数组。
比如输入的是:
期望输出的是:
可能之前我们有所知道一些排序算法,比如SelectionSort,扫描全数组找到最小元素,把它放到输出数组的第一位,接着扫描复制次小的元素,以此类推;比如BubbleSort,对相邻无序的元素进行比较,执行反复的交换,直到最后数组完成排序。等等。但这些算法的问题就是运行时间是平方级的。那我们来看看今天这个排序算法用更少的运行时间是怎么实现的。
例子 想要理解MergeSort算法是如何运行的,一个最简单的方法就是看看具体的例子。
整体过程就是:
它把数组 [5, ,4, 1, 8, 7, 2, 6, 3] 划分为更小的数组(子问题)[5, 4, 1, 8] 和 [7, 2, 6, 3]排序,通过神奇的递归操作,得到每个排序后的子数组,再将子数组合并起来。
伪代码 将上面的图换成伪代码就是这样的过程
而这个Merge程序怎么实现呢?
由上面的图我们可以知道,Merge的时候,其实输入两个已经排序好的数组C, D,再把它们排序输出到B。
索引 k 操控的是输出数组,索引 i,j 操控的是已排序好的C和D子数组,都是从左向右扫描。每一次的for循环,其实就是找C和D中最小的数字,因为C和D是已排序好的数组,所以最小的数字就是i或j对应的元素。比较后把它放入输出数组B中,并将对应的索引+1,这样下次循环就跳过已复制的元素了。所以最后的数组B输出是按序方式生成的。
算法分析
我们先来对Merge程序算算它的执行操作数量。 第1,2行有一次赋值操作。 第3行是一个for循环,每一个for循环里,有比较操作(C[i]和D(i)比较),赋值操作(B[k]的赋值),递增操作(i或j加1),循环变量k还要加1,所以每一次循环一共有4次操作。
一共就是4n+2次操作,为了后面的计算方便,当n>=1时,4n+2<6n(去掉常数项), 我们取6n次操作作为Merge程序操作上界。
我们现在再来看MergeSort的运行时间。 为了简单起见,假如输入数组的长度是n的2次方(如果没有这个假设只需要额外工作就能消除这个假设),我们用递归树的方法来分析运行时间的上界,每一个节点就表示一次递归调用。
最外层是整个原始的输入数组,它在进行MergeSort的时候会有2个递归调用,所以这是一个二叉树(每个节点都有两个子节点),第一层的2个节点就是原始数组的左半部分和右半部分,再次递归最后到达最底层,一个长度为1或0的数组。我们需要知道几个数量:
原始数组长度是n,递归树有多少层?
由于每深入一层,数组长度就缩小一半,第0层是n,第1层是n/2(除了一次2),第2层是n/4(除了2次2),最后一层的数组长度是不大于1的,就是除以了log2(n)次2,所以最后一层是log2(n)层。(也可以假定n/2^a = 1, 求解a)如果没有n是2的次方这个假设,就向上取整。一共就是log2(n) +1层。
递归树的第j层有多少个节点(子问题)?每个节点的数组长度是多少?
因为每一层的递归数量是前一层的两倍,所以第j层就有2^j个子问题。每个节点的长度,总长度是n,均分到每个节点就是n/(2^j)个长度。
所以总的运行时间就是:
层数 * 每一层的工作量
= 层数 * (第 j 层的子问题数量 * 每个第j层子问题完成的工作数) = 层数 * (第 j 层的子问题数量 * (每个第j层子问题的规模 * Merge的时间))
= (log2(n)+1) * ( 2^j * n/(2^j) * 6n)
=6n * log2(n) +6n
= O(nlogx(n))
这时候,我们就可以理直气壮的说递归的分治算法比其它更简单的算法要快的多啦。看图直观感受一下
当数据非常大的时候,它是非常有优势的,指数函数增长十分的缓慢。
今日互动
有什么不明白的欢迎在评论区留言。
 

斯坦福算法分析和设计_2. 排序算法MergeSort的更多相关文章

  1. 在一个N个整数数组里面,有多个奇数和偶数,设计一个排序算法,令所有的奇数都在左边。

    //在一个N个整数数组里面,有多个奇数和偶数,设计一个排序算法,令所有的奇数都在左边. // 例如: 当输入a = {8,4,1,6,7,4,9,6,4}, // a = {1,7,9,8,4,6,4 ...

  2. java排序算法(三):堆排序

    java排序算法(三)堆排序 堆积排序(HeapSort)是指利用堆积树这种结构所设计的排序算法,可以利用数组的特点快速定位指定索引的元素.堆排序是不稳定的排序方法.辅助空间为O(1).最坏时间复杂度 ...

  3. 算法分析中最常用的几种排序算法(插入排序、希尔排序、冒泡排序、选择排序、快速排序,归并排序)C 语言版

    每次开始动手写算法,都是先把插入排序,冒泡排序写一遍,十次有九次是重复的,所以这次下定决心,将所有常规的排序算法写了一遍,以便日后熟悉. 以下代码总用一个main函数和一个自定义的CommonFunc ...

  4. Python排序算法(六)——归并排序(MERGE-SORT)

    有趣的事,Python永远不会缺席! 如需转发,请注明出处:小婷儿的python https://www.cnblogs.com/xxtalhr/p/10800699.html 一.归并排序(MERG ...

  5. 简单排序算法设计(Java)

    总共有八种排序算法,还是慢慢看吧 1.简单排序算法 简单排序算法就是设置标兵,逐个比较数,然后查找插入位置,插入 public static void p(int[] a){ for(int i=0; ...

  6. 排序算法之归并排序(Mergesort)解析

    转自:http://www.cnblogs.com/ayqy/p/4050452.html   一.归并排序的优缺点(pros and cons) 耗费心思来理解它,总要有个理由吧: 归并排序的效率达 ...

  7. 十大经典排序算法总结(JavaScript描述)

    前言 读者自行尝试可以想看源码戳这,博主在github建了个库,读者可以Clone下来本地尝试.此博文配合源码体验更棒哦~~~ 个人博客:Damonare的个人博客 原文地址:十大经典算法总结 这世界 ...

  8. 转载部长一篇大作:常用排序算法之JavaScript实现

    转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...

  9. 常用排序算法之JavaScript实现

    1.插入排序 1)算法简介 插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从 后向前扫描,找到相应位置并插入 ...

随机推荐

  1. java DOM 操作xml

    1 代码如下: package dom.pasing; import java.io.IOException; import java.io.StringWriter; import javax.xm ...

  2. H3C 最大跳数16导致网络尺度小

  3. 【BZOJ 1004】 [HNOI2008]Cards

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1004 [题意] 给你sr+sb+sg张牌,(令n=sr+sb+sg),让你把这n张牌染 ...

  4. electron-vue 窗口拖拽及自定义边框,及关闭缩小放大化方法

    1.窗口的最小化按钮和关闭按钮以及标题栏自定义,不使用 electron 自身携带的原生标题栏 在src文件夹下main下index.js文件添加 mainWindow = new BrowserWi ...

  5. 【React】 npm 常用的插件

    npm install –save-dev    package.json   安装环境 https://segmentfault.com/a/1190000008489881  全局 https:/ ...

  6. 慎用curl测网站速度

    curl的计时功能也许不够准确. curl -s -o /dev/null -w %{time_total} g.cn 耗时(秒) 0.1350.1340.1350.1350.1340.132 ab ...

  7. 11-28-----vertor和list使用场景

    1.vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随机访问,而不子啊胡插入和删除的效率,使用vector, 2.list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关 ...

  8. 2018-2-13-手机1520-win8.1升级win10

    title author date CreateTime categories 手机1520 win8.1升级win10 lindexi 2018-2-13 17:23:3 +0800 2018-2- ...

  9. dotnet 数组自动转基类数组提示 Co-variant array conversion 是什么问题

    在 C# 的语法,可以提供自动将某个类的数组自动转这个类的基类数组的方法,但是这样的转换在 Resharper 会提示 Co-variant array conversion 这是什么问题? 在 C# ...

  10. You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

    异常 You are using the runtime-only build of Vue where the template compiler is not available. Either ...