16 October 2013

无论是插入排序还是归并排序、快速排序,都是建立在比较排序方法上,即通过比较排序。我们来看看一个简单的过程,假设存在三个数字a1,a2,a3:

                     a1 < a2?
                    /        \
            a1 < a3?          a2 < a3?
           /       \         /        \
      a2 < a3?   [2 1 3] a1 < a3?   [1 2 3]
     /       \          /        \ 
   [3 2 1]  [2 3 1]   [3 1 2]   [1 3 2]

方法很简单,如果a1小于a2,比较a1与a3的大小,如果a1大于a3,则排序结果是[2 1 3],后同。如果有n个数,将会有n!种可能的排序结果。而最坏的比较次数如图将是3,即这棵二叉树的深度,假设是d。

事实上,一棵二叉树,最多含有2^d(2的d次方,^表示做指数,后同)个叶节点,所以:

n! ≤ 2^d。

两边取对数,得到:

d ≥ log(n!)

这里对数以2为底数。这时也许你会说,我们找到比较排序的下界了,是log(n!)。事实上,这并不能算一个严格下界。我们需要对log(n!)继续处理。

《算法导论》中的3.18公式明确给出:

log(n!) = Θ(nlogn)

证明方法除了使用Stirling公式以外,可以如下证明:

log(n!) = log1 + ... + logn ≥ n/2 * log(n/2) = n/2 * logn - n/2 = c1 * logn
log(n!) = log1 + ... + logn ≤ nlogn = c2 * logn

于是我们得到上式。由于底2的对数是递增函数,则d ≥ Ω(nlogn)。所以nlogn才是比较排序的上界。堆排序和归并排序都可以达到这个下界。

当然,在一些特殊情况下,能够达到比这个下界还好的时间复杂度,不过对于一般情况,下界便是nlogn。

到这里,也许你会有所疑问,有没有方法能够把这个下界再提高一点。那当然就要靠你的聪明才智了!较为常见的复杂度还有n^a,b^n次方等(a,b均为某常数),想办法向其靠拢吧。

这就是为什么归并排序这么快,因为它已经达到最好的情况(一般情况)了!

参考材料:



blog comments powered by Disqus