算法导论第27章,在并行处理的条件下效率很高的排序算法。

介绍 如下面左图所示,每条横线(wire)代表一个待 比较的数值,竖线(comparator)表示连接的两条横线要做一次比较,并将较小的值放在输出横线的上方,较大的放在下面。排序过程就是从左往右依次 调用各个comparator(在同一位置上的comparator可以同时做) 有图表示了四个数字3, 2, 4, 1在经过这个Sorting Network时的行为。(由于背景为深色,建议点击图片查看)

下图是一个冒泡排序的Sorting Network表示

可以看到所有的比较都没有并行,效率很低。接下来先介绍一个0-1原理,然后利用它来构造一些比较高效的网络。

性质 首先是引理27.1: 对 于输入数据A = <a_1, a_2, .., a_n>,如果某个比较网络(comparison network)的输出是B = <b_1, b_2, …, b_n>,那么对于任一单调递增的函数f,这个网络能把输入数据f(A) = <f(a_1), f(a_2), …, f(a_n)>变为f(B) = <f(b_1), f(b_2), …f(b_3)>

这个引理的证明很简单,关键在于min(f(x), f(y)) = f(min(x,y))

接下来就是0-1原理: 一个有n个输入数据的比较网络,如果它能将仅由0和1组成的序列正确的排序(这种输入共有2^n种可能),那么它也能正确的将任意数字组成的序列排序。 证明也不难,利用前面的引理反正即可得到这个定理。

双调排序 接 下来先考虑双调序列(bitonic sequence)这种特殊情况,所谓双调序列就是先单调递增,后单调递减,或者可以通过环形旋转变化出上述特性的序列,比如<1, 4, 6, 8, 3, 2>和<6, 9, 4, 2, 3, 5>都满足条件(对于后面一种序列,只要把最后的3, 5移到序列开头就行了)。 双调排序(bitonic sorter)有若干步骤,其中有一步叫做half-cleaner,每一次half-cleaner讲数据放到一个深度为1的排序网络中,第i行和第i+n/2行比较(i=1,2,..,n/2)

引理27.3: 做完上述的half-cleaner后,输出的上半部分和下半部分都保持双调的特点,而且上半部分的每个元素都不大于下半部分的任一元素。 分四种情况讨论即可。

通过递归调用half-cleaner即可完成双调队列的排序。要对n个元素进行双调排序Bitonic-Sorter(n),首先调用Half-Cleaner(n),将元素分成上下两部分,接着依次对这两部分执行Bitonic-Sorter(n/2)即可。 调用的深度D(n) = lgn

归并网络 书上只给出了对0-1序列排序的算法,任意数字的排序算法留作了习题。 合并网络基于这样一个事实:对于两个已经排序了的序列X = 00000111,Y = 00001111,将Y倒过来后和X拼接的结果是一个双调序列。对这个双调序列再做一次Bitonic-Sorter就能有序。 通 过修改Bitonic-Sorter方法的第一步就能实现Merger,关键在于隐式的反转输入的下半部分。Half-Cleaner方法中比较了第i和 第i+n/2两个元素,如果下半部分反转的话就相当于比较第i和第n-i+1个元素。直接继续执行Bitonic-Sorter方法即可,如下图所示。

排序网络 我们已经有了构造一个排序网络所需的工具,接下来介绍一种利用归并网络进行排序的并行版本。 大致方法和传统的归并排序类似,从最小的颗粒开始二分增长,直到整个序列有序。 这样,一共需要lg(n)次Merger,每次归并中需要做lg(i)次Sorter,排序的总深度 D(n) = 0               (n = 1) D(n/2) + lg(n)  (n = 2^k且 k>=1) 由Master Method可推出D(n) = big-omega(lg^2(n)) 也就是说理想的并行环境中,n个数可以在O(lg^2(n))时间内完成排序。

Bitonic Sorter http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm

图片来自于Wikipedia以及算法导论附图