普林斯顿大学算法课 Algorithm Part I Week 3 归并排序 Mergesort
起源:冯·诺依曼最早在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的更多相关文章
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity
计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable oper ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 快速排序 Quicksort
发明者:Sir Charles Antony Richard Hoare 基本思想: 先对数据进行洗牌(Shuffle the array) 以数据a[j]为中心进行分区(Partition),使得a ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序的应用 System Sorts
排序算法有着广泛的应用 典型的应用: 排序名称 排序MP3音乐文件 显示Google的网页排名的搜索结果 按标题顺序列出RSS订阅 排序之后下列问题就变得非常简单了 找出中位数(median) 找出统 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 重复元素排序 - 三路快排 Duplicate Keys
很多时候排序是为了对数据进行归类,这种排序重复值特别多 通过年龄统计人口 删除邮件列表里的重复邮件 通过大学对求职者进行排序 若使用普通的快排对重复数据进行排序,会造成N^2复杂度,但是归并排序和三路 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 求第K大数 Selection
问题 给定N个元素的数组,求第k大的数. 特例当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用顺序统计求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability
稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 自我总结
要熟练掌握比较器Comparator public final Comparator<T> MY_COMPARATOR = new myComparator(); //定义比较器 .... ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 比较器 Comparators
比较器接口(Comparator interface):用可选顺序(alternate order)进行排序 public interface Comparator<key> int co ...
- 普林斯顿大学算法课 Algorithm Part I 学习资源
网友笔记参考 果壳Mooc首页 revilwang的专栏 白色咖啡 Weiran Liu的渣技术小专栏 Bug表:http://findbugs.sourceforge.net/bugDescript ...
随机推荐
- To and Fro(字符串水题)
To and Fro 点我 Problem Description Mo and Larry have devised a way of encrypting messages. They first ...
- 【LeetCode练习题】Linked List Cycle II
Linked List Cycle Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it ...
- system函数遇到的问题 - 程序死掉
system函数遇到的问题 解决方案见最下边 http://blog.csdn.net/yangzhenzhen/article/details/51505176 这几天调程序(嵌入式linux),发 ...
- K-th Number(第k大数)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 45710 Accepted: 15199 Ca ...
- [poj 1144]Network[Tarjan求割点]
题意: 求一个图的割点. 输入略特别: 先输入图中点的总数, 接下来每一行首先给出一个点u, 之后给出一系列与这个点相连的点(个数不定). 行数也不定, 用0作为终止. 这样的输入还是要保证以数字读入 ...
- 怎样在xcode中使用storyboard
StoryBoard是iOS 5的新特征,目的是取代历史悠久的NIB/XIB,对于已经习惯了xib文件的孩子们来说,StoryBoard还不是那么熟悉.经过两天的研究,有了一些心得,在此分享. 一.怎 ...
- Android_通过ContentObserver监听短信数据变化
1.简单介绍 在小米等一些机型,无法接收系统发出的短信广播. 仅仅能通过观察者ContentObserver,去监听短信数据的变化 2.SMS数据介绍 content://sms/inbox ...
- HDU 1757 A Simple Math Problem(矩阵高速幂)
题目地址:HDU 1757 最终会构造矩阵了.事实上也不难,仅仅怪自己笨..= =! f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + -- + a9 ...
- 手工删除oracle的方法
大致方法如下: 1.删除物理文件 1.1.oracle安装文件. 1.2.系统目录下,program files文件下的oracle文件 2.注册表中大概有这么几个地方: hkey ...
- jQuery下实现检测指定元素加载完毕
检测元素出现方法.虽然是基于 jQuery 的,但是代码很简洁,可以修改成纯js版的. 文本 jQuery.fn.wait = function (func, times, interval) { v ...