图解合并排序(归并排序)
我们用个简单的例子来看看这是什么意思:
通过此图你可以看到,在 2 个 4元素序列里你只需要迭代一次,就能构建最终的8元素已排序序列,因为两个4元素序列已经排好序了:
- 1) 在两个序列中,比较当前元素(当前=头一次出现的第一个)
- 2) 然后取出最小的元素放进8元素序列中
- 3) 找到(两个)序列的下一个元素,(比较后)取出最小的
- 重复1、2、3步骤,直到其中一个序列中的最后一个元素
- 然后取出另一个序列剩余的元素放入8元素序列中。
这个方法之所以有效,是因为两个4元素序列都已经排好序,你不需要再『回到』序列中查找比较。
【译者注:合并排序详细原理。】
合并排序是把问题拆分为小问题,通过解决小问题来解决最初的问题(注:这种算法叫分治法,即『分而治之、各个击破』)。如果你不懂,不用担心,我第一次接触时也不懂。如果能帮助你理解的话,我认为这个算法是个两步算法:
- 拆分阶段,将序列分为更小的序列
- 排序阶段,把小的序列合在一起(使用合并算法)来构成更大的序列
拆分阶段
在拆分阶段过程中,使用3个步骤将序列分为一元序列。步骤数量的值是 log(N) (因为 N=8, log(N)=3)。
底数为2,道理是每一步都把原序列的长度除以2,步骤数就是你能把原序列长度除以2的次数。这正好是对数的定义(在底数为2时)。
排序阶段
在排序阶段,你从一元序列开始。在每一个步骤中,你应用多次合并操作,成本一共是 N=8 次运算。
- 第一步,4 次合并,每次成本是 2 次运算。
- 第二步,2 次合并,每次成本是 4 次运算。
- 第三步,1 次合并,成本是 8 次运算。
因为有 log(N) 个步骤,整体成本是 N*log(N) 次运算。
合并排序的强大之处
为什么这个算法如此强大?
因为:
- 你可以更改算法,以便于节省内存空间,方法是不创建新的序列而是直接修改输入序列。
注:这种算法叫『原地算法』(in-place algorithm)
- 你可以更改算法,以便于同时使用磁盘空间和少量内存而避免巨量磁盘 I/O。方法是只向内存中加载当前处理的部分。在仅仅100MB的内存缓冲区内排序一个几个GB的表时,这是个很重要的技巧。
注:这种算法叫『外部排序』(external sorting)。
- 你可以更改算法,以便于在 多处理器/多线程/多服务器 上运行。
比如,分布式合并排序是Hadoop(那个著名的大数据框架)的关键组件之一。
这个排序算法在大多数(如果不是全部的话)数据库中使用,但是它并不是唯一算法。如果你想多了解一些,你可以看看 这篇论文,探讨的是数据库中常用排序算法的优势和劣势。
伪代码
1 array mergeSort(array a) 2 if(length(a)==1) 3 return a[0]; 4 end if 5 6 //recursive calls 7 [left_array right_array] := split_into_2_equally_sized_arrays(a); 8 array new_left_array := mergeSort(left_array); 9 array new_right_array := mergeSort(right_array); 10 11 //merging the 2 small ordered arrays into a big one 12 array result := merge(new_left_array,new_right_array); 13 return result;