普林斯顿大学算法课 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 ...
随机推荐
- 1021 Fibonacci Again (hdoj)
Problem Description There are another kind of Fibonacci numbers: F(0) = 7, F(1) = 11, F(n) = F(n-1) ...
- SQL Server 连接和事务相关的问题。
方法 1. dbcc opentran + sys.dm_exec_connections dbcc opentran; dbcc opentran 针对当前数据库 dbcc opentran('St ...
- MYSQL create database 和 create table 做了一些什么!
create database Studio; 这样就可以创建一个数据库了.他包涵一些什么呢? 可以看到它创建了一个文件夹,下面我们进去看一下它里面有一些什么东西. 还是先建一张表再进去吧,运行一下这 ...
- create custom launcher icon 细节介绍
create custom launcher icon 是创建你的Android app的图标 点击下一步的时候,出现的界面就是创建你的Android的图标 Foreground: ” Foregro ...
- Unix/Linux环境C编程入门教程(29) 内存操作那些事儿
函数介绍 memccpy(拷贝内存内容) 相关函数 bcopy,memcpy,memmove,strcpy,strncpy 表头文件 #include<string.h> 定义函数 voi ...
- #pragma pack(n) 的作用
在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float等)的变量,也可以是一些复合数据类型(如数组.结构.联合等)的数据单元.在结构中,编译器为结构的每个成 ...
- Minimum Sum(思维)
Problem 1603 - Minimum Sum Time Limit: 2000MS Memory Limit: 65536KB Total Submit: 563 Accepted ...
- Win32K里的死循环
引用注明>> [作者:张佩][原文:www.YiiYee.cn/blog] 这是我到新公司后上手的第一个issue.一线project师找到我,说有一个urgent issue有没有兴趣看 ...
- jquery选择器从认识到使用初级篇
1. .class 选择器 ---一种通过元素类别属性查找元素 调用格式: $(".class") ----其中参数表示元素的css类别名称(类选择器)<input cl ...
- 根据Model有值的自动生成添加的Sql语句
static string Table_Name = ""; /// <summary> /// model实体中的字段名相对数据库表添加的字段 /// 如: /// ...