Bitonic 似乎是一个双关,既表示 bi + tonic “双调”,即先增后减或先减后增,又可以理解为 bit + onic “关于二进制位的”,提示了里面使用了很多位运算优化。
概述#
由于这个算法是专门为数据并行处理而设计的,可以做到同一层排序内的比较和交换互不依赖,因此只有在并行计算框架下才能发挥出其完全性能。当串行处理时,其复杂度不是最优的,达到了 ,但由于每一层可以完全并行,所以在并行框架下可以达到 .
这个算法类似归并,但将归并中的“合并”(代价 )这一无法并行的操作(双指针步进互相依赖,无法预测)替换为了可以并行的“双调合并”(代价 ,可以并行到 )。
具体地,它有两个递归的任务:
- 将一段双调序列变为一段单调序列
- 将两段相邻的单调性不同的单调序列拼成一段更长的双调序列
为了严谨讨论,我们约定:双调序列的长度为 2 的幂,其前半段递增(递减),后半段递减(递增),并称其为“凸的”(“凹的”)。
刚刚的任务中,1. 自身可以递归 次完成。具体地,当当前双调序列长度为 时,每次依次比较 和 ,其中 ,通过必要的交换保证 ,其中 . 经过操作之后,这个双调序列会变成两个相邻的、凸凹性相反的双调序列,其中凸的序列中的元素都小于等于凹的序列中的元素。这就形成了 和 这两个区间之间的单调性。 继续递归直到 ,此时将会变成单调序列。
综上,任务 1. 可以 地完成,且完成后任务 2. 可以瞬间完成。
总共需要完成 次任务,因此总复杂度 .
上述算法中,高亮的部分可以完全并行。
实现#
实现中,为了发挥并行性能,使用了 PyTorch 框架配合 CUDA/mps.
附录 - 图示#
每个双调序列,递归地变成单调序列。


两个单调性相反的单调序列,拼成一个双调序列。

回溯到更大的问题上,将这个大的双调序列,继续递归地变成单调序列:


排序完成。