最优排序
    前面讨论了很多的排序方法,那么有没有什么方法是最优的呢?有没有什么办法排序是最快的呢?
    答案显然是否定的,什么才算是最优呢?一个排序算法受很多因素的影响,也可以从很多的角度来衡量一个排序算法,有些可能关注比较的次数,有些可能关注记录移动的次数,有些关注额外空间的使用。因此没有最优的排序算法,只有最合适的。但是排序算法中经常关注的就是排序过程中的比较次数,下面讨论一下在基于比较的排序算法中如何用最少的比较次数来排序。
    对N个元素的数组进行比较排序,最终得到有序序列的过程都可以用一个二叉树来表述,如下图所示,其中内节点的两个下标i:j表示 Ki 和Kj进行比较,左子树表示Ki<Kj,右子树表示Ki>Kj, 叶子节点表示最终排序后数组下标值,例如a1, a2, ..., an表示Ka1 < Ka2<...<Kan
 
 
    首先比较K1 K2,如果K1<K2,走左子树,K2和K3比较,如果K2>K3,走右子树,比较K1 K3,K1<K3,则我们知道K1<K3<K2。我们发现2:3比较完之后并没有继续比较1:3,因为K1<K2 而K2<K3,我们已经知道K1<K3了,所以没必要再比较K1 K3了,这是冗余的情况,因此这样的路径是永远走不到的,而我们关心的是最少比较次数,所以这样的情况直接从图中剔除掉了。
这样一棵二叉树的内节点表示了所有可能的输入情况下得到最终有序序列的比较方式, 那么剔除掉冗余情况之后,对n个元素的数组排序,二叉树叶节点的个数为n!,也就是n个元素的所有排列组合情况。
    那么接下来的问题就是在所有可能的排序二叉树中,每棵树的最大比较次数里面的最小值是多少呢?这个最小值也就是对n个元素进行排序的最坏情况下的最少比较次数。
    假设这个最小值为S(n),如果这棵排序二叉树的内节点的层数都<K,显然这棵树最多有 2 k个叶节点。即n! <= 2s(n)
 
     因为S(n)是×××,那么S(n)>= log 2 n!取上限
     在前面介绍的算法中,在最坏情况下拥有最少比较次数算法是binary insertion, tree selection, two-way merging, binary insertion的比较次数为:
     
    在n不是很大的情况下,我们可以计算出比较的次数为:
     
    对于S(4)可以用5次比较得到最终结果,对于S(5),可能是7也可能是8, 那么5个数排序,如何用7次比较来得到结果呢?
    首先比较K1 K2然后比较K3 K4两对的最大值再进行比较,总共比较3次,这样我们可以得到下面的图形:
a到b的箭头表示a<b,接着我们把e插入到a b d之间,那么可能会有下面四种情况:
最多比较两次,e先和b比较,大的话则和d比,小的话则和a比。

最后把c插入到a b d e之间,我们可以发现最多也只需要比较两次,c和e比,小的话则和a比,否则和b比,c和d已经比较过了,不用再比较了。因此总的次数就是3+2+2=7次
那么把这一方法推广到一般化的情况下呢?我们称其为merge insertion方法,下面来看一个21个元素的例子
先取出前10对元素,K1:K2 K3:K4 ... K19:K20两两比较找出最大的,需要10次比较,然后对这些最大的元素使用merge insertion方法排序,需要22次,可以得到下图:
之后将b3插入到b1 a1 a2之间,和前面讨论的一样,需要2次,然后把b2插入进去,也是2次,这样可以得到下面的序列:
我们把最上面一层箭头所指的元素称为主链,也就是已经排好序的元素,接下来可以把b5插入到主链中,需要3次比较,先和c4比,小的话再和c2比,小的话和c1比,否则和c3比,如果比c4大,则和c6比,比c6大则和a4比,否则和c5比,类似的我们可以用3次比较把b4插入到主链。得到下图:
接下来是最关键的一步,我们把b11插入到主链,而不是b6,使用4次比较,既先和d8比,然后和d4或a7比,然后和d2或者d6或者d10或者a9比,最后再比一次,总共4次。接下来依次将b10 b9 b8 b7 b6插入到序列中,每个需要4次,因此总的比较次数为20+22+2+2+3+3+4+4+4+4+4+4=66次,因为 265<21!< 266
因为S(21)=66,因此我们 对21个数进行排序,最少要66次。为什么要先插入b11呢?我们可以发现,主链上面的元素为15个,通过二分法,4次比较可以找到合适的插入位置,但是如果先插入b6到b10之间的元素,则主链元素为16个,最坏要5次才能把b11插入进去了。那么为什么先插入b10而不是b6呢?当b11插入到主链之后,主链个数为16个,但是b10和a10已经比较过了,因此只要在前面15个元素里面找到合适的位置,只需要4次,而如果先插入b6的话,b6前面有10个元素,最坏也要4次,即使把后面5个元素都插入到a6之前也才15个,也只要4次,因此我们插入的顺序是b11 b10 ... b6,这样将最坏情况下的总的比较次数降到了最低。把这最关键的地方弄清楚之后,就可以开始推广到n的情况了,下面就是merge insertion算法的描述
1、将n个元素两个一对比较,找出每对最大的(如果n为偶数,则最后没有剩余的元素)
2、通过merge insertion对这2/n个数进行排序
3、对这些元素分别命名为a1,a2,...,a2/n  b1,b2, ... , b2/n如果n为奇数则是b(2/n+1)  其中a1 < a2 < ... < a2/n  ai<bi
b1和a一起称为主链,后面的工作就是要把其余的b使用二分插入法插入到主链中去。剩余元素的插入顺序为:
接下来的任务就是要定义(t1, t2, t3, t4,...)=(1,3,5,11,...)这样一个序列,那么就可以按照
的顺序使用k次比较来将这些元素插入到主链中去了,这是这个链如下图所示:
我们知道主链包含节点At(k-1)的总节点个数为: 2T k-1  + (T k -T k-1  -1) = T k-1  + T k  -1   这个数肯定小于2k,最好等于2k-1
既:Tk-1 + Tk = 2k 
 T1=1 我们假设T0=1
这样就可以求出这个序列的取值了。
 
总结:这是昨天晚上看《The Art of Computer Programming》时看到了,理解了很久才算入了点门,后面的分析略过去了,有兴趣的朋友可以找到书看,算法的思想确实很巧妙,而且分析得相当的透彻,我们平时也没有谁会为了节省几次比较操作而去研究如何让排序过程中的比较次数最少吧,最关键的还是通过这个算法了解作者如何分析问题,推广问题,最终解决问题的方法。