我正在尝试实现http://arxiv.org/pdf/1008.2849v2.pdf(算法2)中描述的并行基数排序变体,但我的C ++实现(基数10中的4位数)包含一个我无法找到的错误。
出于调试目的,我没有使用并行性,但代码仍应正确排序。
例如,行arr.at(i) = item
在以下
std::vector<int> v = {4612, 4598};
radix_sort2(v);
我的实施如下
#include <set>
#include <array>
#include <vector>
void radix_sort2(std::vector<int>& arr) {
std::array<std::set<int>, 10> buckets3;
for (const int item : arr) {
int d = item / 1000;
buckets3.at(d).insert(item);
}
//Prefix sum
std::array<int, 10> outputIndices;
outputIndices.at(0) = 0;
for (int i = 1; i < 10; ++i) {
outputIndices.at(i) = outputIndices.at(i - 1) +
buckets3.at(i - 1).size();
}
for (const auto& bucket3 : buckets3) {
std::array<std::set<int>, 10> buckets0, buckets1;
std::array<int, 10> histogram2 = {};
for (const int item : bucket3) {
int d = item % 10;
buckets0.at(d).insert(item);
}
for (const auto& bucket0 : buckets0) {
for (const int item : bucket0) {
int d = (item / 10) % 10;
buckets1.at(d).insert(item);
int d2 = (item / 100) % 10;
++histogram2.at(d2);
}
}
for (const auto& bucket1 : buckets1) {
for (const int item : bucket1) {
int d = (item / 100) % 10;
int i = outputIndices.at(d) + histogram2.at(d);
++histogram2.at(d);
arr.at(i) = item;
}
}
}
}
有人能发现我的错误吗?
答案 0 :(得分:1)
我看了你链接的那篇论文。你没有犯过任何错误,我没有看到任何错误。事实上,根据我的估计,你纠正了算法中的错误。
我写出了算法并最终得到了与你完全相同的问题。在复习算法2后,要么我错误地理解它应该如何工作,要么就是有缺陷的。该算法至少存在一些问题,特别是围绕outputIndices
和histogram2
。
查看算法,项目的最终索引由outputIndices
中存储的计数排序确定。 (现在让我们忽略直方图)。
如果你有一个数字的初始数组{0100, 0103, 0102, 0101}
那么前缀的总和就是4。
该算法没有表明我可以确定将结果滞后1.可以说,为了使算法以他们想要的方式工作,它确实必须滞后,因此,继续前进。
现在,前缀总和为0, 4, 4...
。该算法不使用MSD作为outputIndices
数组的索引,它使用“MSD - 1”;因此,将1作为数组的索引,没有直方图的第一项的起始索引是4!在第一次尝试之外的数组。
outputIndices
是使用MSD构建的,MSD可以访问它。
此外,即使您正确调整算法以将MSD用于outputIndices
,它仍然无法正确排序。使用初始输入(交换){4598, 4612}
,它们将保持该顺序。它们(本地)排序,就好像它们是2位数字一样。如果将其增加为其他数字不以4开头,则它们将全局排序,但本地排序永远不会完成。
根据该论文,目标是使用直方图来做到这一点,但我没有看到这种情况发生。
最终,我假设,你想要的是一种按照描述的方式工作的算法。我修改了算法,保持了使用MSD进行全局排序的纸张的总体规定目标,以及反向LSD的其余数字。 我认为这些改变不会影响您对并行功能的愿望。
void radix_sort2(std::vector<int>& arr)
{
std::array<std::vector<int>, 10> buckets3;
for (const int item : arr)
{
int d = item / 1000;
buckets3.at(d).push_back(item);
}
//Prefix sum
std::array<int, 10> outputIndices;
outputIndices.at(0) = 0;
for (int i = 1; i < 10; ++i)
{
outputIndices.at(i) = outputIndices.at(i - 1) + buckets3.at(i - 1).size();
}
for (const auto& bucket3 : buckets3)
{
if (bucket3.size() <= 0)
continue;
std::array<std::vector<int>, 10> buckets0, buckets1, buckets2;
for (const int item : bucket3)
buckets0.at(item % 10).push_back(item);
for (const auto& bucket0 : buckets0)
for (const int item : bucket0)
buckets1.at((item / 10) % 10).push_back(item);
for (const auto& bucket1 : buckets1)
for (const int item : bucket1)
buckets2.at((item / 100) % 10).push_back(item);
int count = 0;
for (const auto& bucket2 : buckets2)
{
for (const int item : bucket2)
{
int d = (item / 1000) % 10;
int i = outputIndices.at(d) + count;
++count;
arr.at(i) = item;
}
}
}
}
对于可扩展性,创建一个执行本地排序的辅助函数可能是有意义的。您应该能够扩展它以处理任意数量的数字。