Параллельная сортировка по радиусу с виртуальной памятью и комбинированием записи

Я пытаюсь реализовать вариант параллельной сортировки по основанию, описанный в http://arxiv.org/pdf/1008.2849v2.pdf (Алгоритм 2), но моя реализация на C++ (для 4 цифр в базе 10) содержит ошибку, которую я Я не могу найти.

В целях отладки я не использую параллелизм, но код все равно должен сортироваться правильно.

Например, линия 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;
            }
        }
    }
}

Кто-нибудь может определить мою ошибку?

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}они останутся в таком порядке. Они отсортированы (локально), как если бы они были двухзначными числами. Если вы увеличите его, чтобы другие числа не начинались с 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;
            }
        }
    }
}

Для расширяемости, вероятно, имеет смысл создать вспомогательную функцию, которая выполняет локальную сортировку. Вы должны быть в состоянии расширить его, чтобы обрабатывать любое количество цифр таким образом.

Другие вопросы по тегам