并行与分布式系统中的并行双调归并网络:双调排序器(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模型)下的时间复杂度和效率。


二、预备知识

  1. 比较器(Comparator):一个基本单元,有两个输入 \(a\)\(b\),两个输出 \(\min(a, b)\)\(\max(a, b)\)。在硬件或并行程序中,比较器可以同时操作。
  2. 排序网络(Sorting Network):由一系列固定连接、固定顺序的比较器组成的电路或算法。其结构是数据无关的(即比较顺序不依赖输入值)。
  3. 双调序列(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}\)(先非递减后非递增),或
      • 序列经过循环移位后能满足上述条件(即允许“先增后减”的模式从中间开始)。
    • 关键性质:两个双调序列可以通过一个双调归并网络合并成一个有序序列。

三、算法核心思想与步骤

步骤1:理解双调归并网络(Bitonic Merging Network)

给定一个长度为 \(n\)(假设 \(n\) 是2的幂)的双调序列,双调归并网络可以将其排序为单调(递增或递减)序列。

操作过程(以排序为递增序列为例):

  1. 将输入序列分成两半:前半部分 \(A = a_0, a_1, \dots, a_{n/2-1}\) 和后半部分 \(B = a_{n/2}, a_{n/2+1}, \dots, a_{n-1}\)
  2. 并行比较-交换操作:对于 \(i = 0, 1, \dots, n/2-1\),比较 \(a_i\)\(a_{i+n/2}\)
    • 将较小的元素放到 \(a_i\) 的位置(称为“min”输出),
    • 将较大的元素放到 \(a_{i+n/2}\) 的位置(称为“max”输出)。
  3. 递归处理:经过第一步后,前一半序列 \(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. 将输入序列分成两半。
  2. 递归地对前半部分进行递增排序,对后半部分进行递减排序(或反之,但需保持一致规则)。
  3. 此时,整个序列是一个双调序列(因为前半部分是递增的,后半部分是递减的)。
  4. 调用双调归并网络(步骤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:关键细节与优化

  1. 非2的幂的处理:可以填充元素到2的幂,或者使用更通用的双调排序变种(如通过零填充)。
  2. 比较方向控制:通过一个标志位控制排序是递增还是递减,在硬件中可通过简单电路实现。
  3. 实际并行实现:在GPU(如CUDA)或多核CPU上,通过线程块和共享内存实现比较-交换操作。例如,在CUDA中,可以使用双调排序内核(bitonic sort kernel),逐步增加比较间距(从2到 \(n\)),每步内并行比较。
  4. 与快速排序对比:双调排序的优势在于其确定性和固定比较模式,适合硬件实现(如FPGA)或SIMD并行;缺点是总比较次数较多(\(O(n \log^2 n)\)),因此在小规模或串行环境下不如快速排序高效。

四、总结

  • 双调排序器是一个经典的并行排序网络,基于双调序列的递归归并。
  • 核心步骤:先递归构建双调序列(前半递增,后半递减),然后通过双调归并网络合并排序。
  • 并行效率:在 \(n\) 个处理器的理想并行模型中,时间复杂度为 \(O(\log^2 n)\),适合固定结构的并行硬件实现。
  • 应用场景:早期并行机(如ILLIAC IV)、GPU排序(如CUDA示例代码)、专用排序硬件。

通过理解双调序列的性质和递归归并过程,你可以掌握这一并行排序算法的精髓,并将其应用于需要高并行度的排序任务中。

并行与分布式系统中的并行双调归并网络:双调排序器(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}\)(先非递减后非递增),或 序列经过循环移位后能满足上述条件(即允许“先增后减”的模式从中间开始)。 关键性质:两个双调序列可以通过一个双调归并网络合并成一个有序序列。 三、算法核心思想与步骤 步骤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示例代码)、专用排序硬件。 通过理解双调序列的性质和递归归并过程,你可以掌握这一并行排序算法的精髓,并将其应用于需要高并行度的排序任务中。