起源:冯·诺依曼最早在EDVAC上实现

基本思想:

  • 将数组一分为(Divide array into two halves)
  • 对每部分进行递归式地排序(Recursively sort each half)
  • 合并两个部分(Merge two halves)

归并排序体现的是一种分治思想(Divide and conquer)

演示: 

1. 给出原数组a[],该数组的lo到mid,mid+1到hi的子数组是各自有序的。

2. 将数组复制到辅助数组(auxiliary array)中,给两部分的首元素分别以i和j的下标,给原数组首元素以k的下标

3. 比较i下标和j下标的元素,将较小值赋到k下标位置的元素内,然后对k和赋值的下标进行递增;
    该演示里j下标的元素比较小,于是将A赋到k的位置里,再对k和j递增,即j+1, k+1

4. 重复上述过程,直到比较完全部元素。


在Java中的实现

public class Merge
{
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi)
{
assert isSorted(a, lo ,mid); //检查a[lo..mid]是否有序
assert isSorted(a, mid + 1, hi); //检查a[mid+1..hi]是否有序 for(int k = lo; k <= hi; k++) //复制数组
aux[k] = a[k]; int i = lo, j = mid + 1;
for(int k = lo; k <= hi; k++)
{
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (less(aux[j], aux[i])) a[k] = aux[j++];
else a[k] = aux[i++];
} assert isSorted(a, lo, hi);
} private static void sort(Comparable[] a, Comparable[] aux, int low, int hi)
{
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
} public static void sort(Comparable[] a)
{
aux = new Comparable[a.length];
sort(a, aux, 0, a.length - 1);
}
}

注:Assert(断言)功能:检查表达式内的值,若为true,则程序正常运行,若为false,则抛出异常,终止运行。

性能分析:

算法复杂度为N*log(N)


优化:

问题:归并排序需要根据数组大小N开辟额外的内存

原地算法(in-place Algorithm):占用额外空间小于等于c log(N)的排序算法。

插入排序、选择排序、希尔排序都属于原地算法。归并排序不属于原地算法。Wiki参考

Kronrod在1969年发明了原地归并排序(in-place merge),不过看起来好像不是那么有用(Challenge for the bored)

实践上的改善(practical improvements)

改善1:对小数组使用插入排序

  • 归并排序要为小的子数组的开辟投入很多开销(开辟数组除了元素占用内存,数组本身还有固定的开销)
  • 当子数组大小超过7,停止(Cutoff)使用插入排序
private static void sort(Comparable[] a, Comparable[] aux, int low, int hi)
{
if (hi <= lo + CUTOFF - 1)
{
Insertion.sort(a, lo, hi);
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
}

改善2:当数组排序好时,停止计算

  • 两部分都已经排序完毕后,若前半部分的最后一个元素大于后半部分的第一个元素,则证明整个序列都是有序的。
private static void sort(Comparable[] a, Comparable[] aux, int low, int hi)
{
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
if (!less(a[mid + 1], a[mid])) return;
merge(a, aux, lo, mid, hi);
}

利用循环实现归并排序:Bottom-up mergesort

简单思路:循环的每一步都对上一步子数组的二倍长度做merge

普林斯顿大学算法课 Algorithm Part I Week 3 归并排序 Mergesort的更多相关文章

  1. 普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity

    计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable oper ...

  2. 普林斯顿大学算法课 Algorithm Part I Week 3 快速排序 Quicksort

    发明者:Sir Charles Antony Richard Hoare 基本思想: 先对数据进行洗牌(Shuffle the array) 以数据a[j]为中心进行分区(Partition),使得a ...

  3. 普林斯顿大学算法课 Algorithm Part I Week 3 排序的应用 System Sorts

    排序算法有着广泛的应用 典型的应用: 排序名称 排序MP3音乐文件 显示Google的网页排名的搜索结果 按标题顺序列出RSS订阅 排序之后下列问题就变得非常简单了 找出中位数(median) 找出统 ...

  4. 普林斯顿大学算法课 Algorithm Part I Week 3 重复元素排序 - 三路快排 Duplicate Keys

    很多时候排序是为了对数据进行归类,这种排序重复值特别多 通过年龄统计人口 删除邮件列表里的重复邮件 通过大学对求职者进行排序 若使用普通的快排对重复数据进行排序,会造成N^2复杂度,但是归并排序和三路 ...

  5. 普林斯顿大学算法课 Algorithm Part I Week 3 求第K大数 Selection

    问题 给定N个元素的数组,求第k大的数. 特例当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用顺序统计求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小 ...

  6. 普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability

    稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插 ...

  7. 普林斯顿大学算法课 Algorithm Part I Week 3 自我总结

    要熟练掌握比较器Comparator public final Comparator<T> MY_COMPARATOR = new myComparator(); //定义比较器 .... ...

  8. 普林斯顿大学算法课 Algorithm Part I Week 3 比较器 Comparators

    比较器接口(Comparator interface):用可选顺序(alternate order)进行排序 public interface Comparator<key> int co ...

  9. 普林斯顿大学算法课 Algorithm Part I 学习资源

    网友笔记参考 果壳Mooc首页 revilwang的专栏 白色咖啡 Weiran Liu的渣技术小专栏 Bug表:http://findbugs.sourceforge.net/bugDescript ...

随机推荐

  1. Jquery基础之ajax

    ajax是Asynchronous JavaScript and XML(异步JavaScript和XML)的简称,ajax并不是单一的技术而是利用一系列交互网页应用相关的技术形成的结合体,ajax揭 ...

  2. ca 证书、签名

    1.我现在没有个人CA证书,使用.中信建投网上交易,是如何保障安全的呢? 如果您目前没有个人CA证书,使用.中信建投网上交易,系统其实也是用CA证书的RSA体系进行加密的. 您在输入账户和密码进行登录 ...

  3. Python中metaclass解释

    Classes as objects 首先,在认识metaclass之前,你需要认识下python中的class.python中class的奇怪特性借鉴了smalltalk语言.大多数语言中,clas ...

  4. Java常见序列化与反序列方法总结

    很多商业项目用到数据库.内存映射文件和普通文件来完成项目中的序列化处理的需求,但是这些方法很少会依靠于Java序列化.本文也不是用来解释序列化的,而是一起来看看面试中有关序列化的问题,这些问题你很有可 ...

  5. 10年程序员谈.Net程序员的职业规划(图/文)

    原文地址:http://bbs.csdn.net/topics/390736769 从事Dotnet程序开发工作近10年了,从开始的月薪3k的小程序员菜鸟,到现在年薪60w的项目总经理,从战战兢兢的去 ...

  6. HDU1879 继续畅通工程 (并查集)

    继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  7. hdu 2222 Keywords_ac自动机模板

    题意:给你n个单词,再给你一串字符,求在字符中有多少个单词出现过 #include <iostream> #include<cstdio> #include<cstrin ...

  8. 【学习总结】autostart 与 init

    学习总结/etc/xdg/autostart/xxx.desktop,是开机从登录界面跳转到桌面启动的,可以拿到桌面环境变量,用户id是“普通用户”,如果自启动的程序文件所属者为root,则需要 执行 ...

  9. ios ViewController present不同的方向

    First ViewController CATransition *transition = [CATransition animation]; transition.duration = 0.3; ...

  10. OC基础14:使用文件

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.对于NSFileManager类,文件 ...