并行与分布式系统中的并行双调归并网络:双调排序器(Bitonic Sorter)算法
字数 2968 2025-12-09 20:13:03
并行与分布式系统中的并行双调归并网络:双调排序器(Bitonic Sorter)算法
一、题目描述
在并行计算中,排序是一个基础且重要的问题。双调排序器是一种基于比较的并行排序网络,它可以在拥有 \(n\) 个处理器的并行系统上,在 \(O(\log^2 n)\) 的时间内对 \(n\) 个元素进行排序。题目要求理解并掌握双调序列(Bitonic Sequence)的定义、双调归并网络(Bitonic Merging Network)的工作原理,以及如何递归构建完整的双调排序网络(Bitonic Sorting Network),并分析其在并行计算模型(如PRAM模型)下的时间复杂度和效率。
二、预备知识
- 比较器(Comparator):一个基本单元,有两个输入 \(a\) 和 \(b\),两个输出 \(\min(a, b)\) 和 \(\max(a, b)\)。在硬件或并行程序中,比较器可以同时操作。
- 排序网络(Sorting Network):由一系列固定连接、固定顺序的比较器组成的电路或算法。其结构是数据无关的(即比较顺序不依赖输入值)。
- 双调序列(Bitonic Sequence):
- 定义:一个序列 \(a_0, a_1, \dots, a_{n-1}\) 是双调的,如果存在一个索引 \(k\) (\(0 \le k < n\)),使得:
- \(a_0 \le a_1 \le \dots \le a_k \ge a_{k+1} \ge \dots \ge a_{n-1}\)(先非递减后非递增),或
- 序列经过循环移位后能满足上述条件(即允许“先增后减”的模式从中间开始)。
- 关键性质:两个双调序列可以通过一个双调归并网络合并成一个有序序列。
- 定义:一个序列 \(a_0, a_1, \dots, a_{n-1}\) 是双调的,如果存在一个索引 \(k\) (\(0 \le k < n\)),使得:
三、算法核心思想与步骤
步骤1:理解双调归并网络(Bitonic Merging Network)
给定一个长度为 \(n\)(假设 \(n\) 是2的幂)的双调序列,双调归并网络可以将其排序为单调(递增或递减)序列。
操作过程(以排序为递增序列为例):
- 将输入序列分成两半:前半部分 \(A = a_0, a_1, \dots, a_{n/2-1}\) 和后半部分 \(B = a_{n/2}, a_{n/2+1}, \dots, a_{n-1}\)。
- 并行比较-交换操作:对于 \(i = 0, 1, \dots, n/2-1\),比较 \(a_i\) 和 \(a_{i+n/2}\):
- 将较小的元素放到 \(a_i\) 的位置(称为“min”输出),
- 将较大的元素放到 \(a_{i+n/2}\) 的位置(称为“max”输出)。
- 递归处理:经过第一步后,前一半序列 \(A'\) 和后一半序列 \(B'\) 分别仍然是双调序列,并且 \(A'\) 中的所有元素都小于等于 \(B'\) 中的所有元素。然后,对 \(A'\) 和 \(B'\) 分别递归应用相同的双调归并过程,直到子序列长度为1。
图示理解(以 \(n=8\) 为例):
- 初始双调序列:\([3, 5, 8, 9, 7, 6, 4, 2]\)(先增后减)。
- 第一步比较-交换对(间距4):(3,7)→(3,7),(5,6)→(5,6),(8,4)→(4,8),(9,2)→(2,9)。得到:\([3, 5, 4, 2, 7, 6, 8, 9]\)。
- 递归处理前4个元素和后4个元素(间距2,然后间距1),最终得到有序递增序列。
时间复杂度:在并行计算中,每一步比较-交换都是并行的,归并整个长度为 \(n\) 的双调序列需要 \(O(\log n)\) 步。
步骤2:构建完整的双调排序网络(Bitonic Sorting Network)
如果输入序列是任意无序的,我们需要先将其构造成双调序列,然后调用双调归并网络。
递归构建过程(假设 \(n\) 是2的幂):
- 将输入序列分成两半。
- 递归地对前半部分进行递增排序,对后半部分进行递减排序(或反之,但需保持一致规则)。
- 此时,整个序列是一个双调序列(因为前半部分是递增的,后半部分是递减的)。
- 调用双调归并网络(步骤1)将整个序列排序为递增(或递减)序列。
例子(\(n=8\)):
- 输入:\([3, 1, 4, 9, 6, 2, 8, 5]\)。
- 递归拆分:
- 对前4个 \([3,1,4,9]\) 按递增排序 → \([1,3,4,9]\)。
- 对后4个 \([6,2,8,5]\) 按递减排序 → \([8,6,5,2]\)。
- 拼接得到双调序列:\([1,3,4,9,8,6,5,2]\)。
- 调用双调归并网络(步骤1)进行全序列递增排序。
并行执行:每一层递归可以并行进行,且双调归并的每一步也是并行的。
步骤3:分析并行复杂度(以PRAM模型为例)
- 双调归并网络深度(步数):\(D_{\text{merge}}(n) = \log n\)(因为每次递归规模减半,每一步并行比较)。
- 双调排序网络总深度(步数):
- 递归关系:\(D_{\text{sort}}(n) = D_{\text{sort}}(n/2) + D_{\text{merge}}(n)\)。
- 解得:\(D_{\text{sort}}(n) = (\log n)(\log n + 1)/2 = O(\log^2 n)\)。
- 总比较器数量(工作量):\(C(n) = (n/4) \log n (\log n + 1) = O(n \log^2 n)\)。
- 在PRAM-CREW模型(并发读互斥写)下,每一步需要 \(O(1)\) 时间,因此并行时间为 \(O(\log^2 n)\),使用 \(n\) 个处理器。
步骤4:关键细节与优化
- 非2的幂的处理:可以填充元素到2的幂,或者使用更通用的双调排序变种(如通过零填充)。
- 比较方向控制:通过一个标志位控制排序是递增还是递减,在硬件中可通过简单电路实现。
- 实际并行实现:在GPU(如CUDA)或多核CPU上,通过线程块和共享内存实现比较-交换操作。例如,在CUDA中,可以使用双调排序内核(bitonic sort kernel),逐步增加比较间距(从2到 \(n\)),每步内并行比较。
- 与快速排序对比:双调排序的优势在于其确定性和固定比较模式,适合硬件实现(如FPGA)或SIMD并行;缺点是总比较次数较多(\(O(n \log^2 n)\)),因此在小规模或串行环境下不如快速排序高效。
四、总结
- 双调排序器是一个经典的并行排序网络,基于双调序列的递归归并。
- 核心步骤:先递归构建双调序列(前半递增,后半递减),然后通过双调归并网络合并排序。
- 并行效率:在 \(n\) 个处理器的理想并行模型中,时间复杂度为 \(O(\log^2 n)\),适合固定结构的并行硬件实现。
- 应用场景:早期并行机(如ILLIAC IV)、GPU排序(如CUDA示例代码)、专用排序硬件。
通过理解双调序列的性质和递归归并过程,你可以掌握这一并行排序算法的精髓,并将其应用于需要高并行度的排序任务中。