起源:冯·诺依曼最早在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

最新文章

  1. Python,Jupyter Notebook,IPython快速安装教程
  2. spring spel
  3. Electron实战:创建ELectron开发的window应用安装包
  4. Selenium IDE- 不同的浏览器
  5. 【BZOJ】【1529】 【POI2005】ska Piggy banks
  6. WinForms 新窗体后台打开完美的解决
  7. C++ 我想这样用(一)
  8. 给sqlserver配置内存参数
  9. selenium webdriver使用过程中出现Element is not currently visible and so may not be interacted with的处理方法
  10. iOS通知NSNotificationCenter
  11. 使用阿里百川HotFix
  12. God 1.1.1 多线程之内存可见性
  13. wrk编译报错gcc: Command not found
  14. SQL SERVER中的两种常见死锁及解决思路
  15. jmeter环境配置
  16. io.netty.resolver.dns.DnsNameResolverContext
  17. 最近公共祖先(LCA)模板
  18. 【转】Python之xml文档及配置文件处理(ElementTree模块、ConfigParser模块)
  19. laravel 打印完整sql语句
  20. C#工程详解

热门文章

  1. Mfgtool
  2. SQL Server 中索引的禁用与删除
  3. MYSQL 数据类型的 3 个注意
  4. Linux基本命令(开发常用的、电脑常用的)
  5. 命令行解释器(shell)
  6. stl入门--reverse函数
  7. js LocalStorage
  8. OC基础9:预处理程序
  9. The Balance(母函数)
  10. 菜鸟必须知道的linux的文件目录结构