我正在移植使用std::nth_element
和std::partition
到OpenCL的C ++代码。
nth_element
是一个selection algorithm,它将第n个最小数字放在第n个点的数组中,并排列其余元素,以便所有小于此数字的元素都在数组之前,以及比它更大的所有元素。实际上,nth_element
将数组排序为3个桶:数字本身,所有小于它的数字,以及所有大于它的数字。
通常,使用递归分区实现nth_element
:选择一个元素,根据元素是否小于此元素对元素进行分区。然后,选择包含数组第n个元素的存储桶并递归该存储桶。 nth_element
和完全快速排序之间的主要区别在于快速排序在两个桶上进行递归,而不仅仅是包含第n个元素的桶。
partition
是nth_element
的较弱版本,它只将数组分为2个桶:条件为true的那些,以及为false的那些桶。我链接的网站提供了实施:
while (first!=last) {
while (pred(*first)) {
++first;
if (first==last) return first;
}
do {
--last;
if (first==last) return first;
} while (!pred(*last));
swap (*first,*last);
++first;
}
return first;
其中pred是一个函数,用于评估元素是否应该在第一个存储桶中。基本上,这个函数迭代地找到数组中最外面的一对元素,这些元素位于错误的位置,然后交换它们,当元素对是相同的元素时停止。
以下是关于并行nth_element
和partition
的初步想法:
可以使用原子比较和交换来实现分区,但我不确定如何覆盖可以交换的所有可能的值对。没有明显的方法可以在多个线程之间划分工作,因为分区需要比较可能彼此相邻的元素或者在数组的相对两端。我也没有办法避免让线程B与已经被线程A交换的元素进行比较,这是低效的。
nth_element似乎更不可并行化,因为它是递归的:每个分区都依赖于前一个分区已经部分排序的元素。
据推测,对于这两种功能而言,有效的并行化策略需要与典型的串行代码完全不同的方法。
nth_element
和partition
的高效并行实施是否已经存在?如果没有,什么是良好的并行化策略?
答案 0 :(得分:2)
Cuda THRUST已实施分区功能(http://docs.nvidia.com/cuda/thrust/index.html#reordering)。
主要思想应该是: 使用前缀和来计算数组中元素的位置,然后重新排列数组。