2016-10-25 9 views
1

Я пытаюсь написать быстрый алгоритм для сортировки вектора большого количества целых чисел, например:Используя рекурсивные базисных роды параллельно ведра сортировки

159 14 5 97 6 54

до сих пор, моя программа разбивает вектор в небольшие ведра по МСДУ, как:

bucket[1]:159 14 
bucket[5]:5 54 
bucket[6]:6 
bucket[9]:97 

и теперь я должен использовать рекурсивный базисного род для сортировки ведра в наиболее значимых порядка цифр:

bucket[1]:14 159 
bucket[5]:5 54 
bucket[6]:6 
bucket[9]:97 

Это рекурсивный радикс код, который я нашел в Интернете:

// Sort 'size' number of integers starting at 'input' according to the 'digit'th digit 
// For the parameter 'digit', 0 denotes the least significant digit and increases as significance does 
void radixSort(int* input, int size, int digit){ 
    if (size == 0) 
    return; 

    int[10] buckets; // assuming decimal numbers 

    // Sort the array in place while keeping track of bucket starting indices. 
    // If bucket[i] is meant to be empty (no numbers with i at the specified digit), 
    // then let bucket[i+1] = bucket[i] 

    for (int i = 0; i < 10; ++i) 
    { 
    radixSort(input + buckets[i], buckets[i+1] - buckets[i], digit+1); 
    } 
} 

Я не знаю, как реализовать этот бит в мой код, я не уверен, о том, что ведро [] делать в коде выше , Может ли кто-нибудь объяснить, какие изменения я должен внести? Вот многопоточный код, который я использую, который плохо работает, так как я не использую рекурсивный.

void sort(unsigned int numCores, std::vector<unsigned int> numbersToSort){ 
// ******************Stage 1**************** 
// Use multithread to seperate numbers into buckets using the most significant digits 
    auto smallbuckets = std::vector<std::shared_ptr<std::vector<std::vector<unsigned int>>>>(); 
    std::mutex mutex; 

    unsigned int workload = numbersToSort.size()/numCores; 

    std::function<void(unsigned int, unsigned int, unsigned int)> put_small_buckets; 
    put_small_buckets = [this, &smallbuckets, &mutex] 
(unsigned int id, unsigned int start, unsigned int end) { 

    auto buckets = std::make_shared<std::vector<std::vector<unsigned int>>>(std::vector<std::vector<unsigned int>>()); 
    for (int j = 0; j < 10; ++j) { 
     buckets->push_back(std::vector<unsigned int>()); 
    } 

    for (unsigned int i = start; i < end; ++i) { 
     unsigned int a = numbersToSort[i]; 
     std::string tmp = std::to_string(a); 
     char c = tmp.at(0); 
     int ia = c - '0'; 
     (*buckets)[ia].push_back(numbersToSort[i]); 
    } 
    std::lock_guard<std::mutex> lock(mutex); 
    smallbuckets.push_back(buckets); 
    }; 

// create a container of threads 
    std::vector<std::shared_ptr<std::thread>> containerOfThreads; 

// create threads and add them to the container. 
    for (unsigned int i = 0; i < numCores; ++i) { 
    // start the thread. 
    unsigned int start = workload * i; 
    unsigned int end = workload * (i + 1); 
    if(i == numCores - 1) end = this->numbersToSort.size() ; 
    containerOfThreads.push_back(std::make_shared<std::thread>(put_small_buckets, i, start, end)); 
    } 

// join all the threads back together. 
    for (auto t : containerOfThreads) t->join(); 

    numbersToSort.clear(); 
// ******************Stage 2**************** 
// Put small multithreaded buckets back to the bucket of radix(10) 

    auto bigbuckets = std::vector<std::shared_ptr<std::vector<unsigned int>>>(); 
    for (int j = 0; j < 10; ++j) { 
    bigbuckets.push_back(std::make_shared<std::vector<unsigned int>>(std::vector<unsigned int>())); 
    } 

int current_index = 10; 

std::function<void()> collect; 
collect = [this, &smallbuckets, &current_index, &mutex, &collect, &bigbuckets]() { 
    mutex.lock(); 
    int index = --current_index; 
    mutex.unlock(); 
    if (index < 0) return; 
    auto mybucket = bigbuckets[index]; 
    for (auto i = smallbuckets.begin(); i != smallbuckets.end(); ++i) { 
     mybucket->insert(mybucket->end(), (*(*i))[index].begin(), (*(*i))[index].end()); 
    } 
    collect(); 
    }; 

// create a container of threads 
    containerOfThreads.clear(); 

// create threads and add them to the container. 
    for (unsigned int i = 0; i < numCores; ++i) { 
    containerOfThreads.push_back(std::make_shared<std::thread>(collect)); 
    } 

// join all the threads back together. 
    for (auto t : containerOfThreads) t->join(); 

// ******************Stage 3**************** 
// Sort big buckets 

    for (int j = 0; j < 10; ++j) { 
    bigbuckets.push_back(std::make_shared<std::vector<unsigned int>>(std::vector<unsigned int>())); 
    } 
    std::function<void(unsigned int, unsigned int)> sort_big_buckets; 
    sort_big_buckets = [this, &bigbuckets, &mutex] 
    (unsigned int start, unsigned int end) { 
    unsigned int curr = start; 
    while(curr < end){ 

     auto mybucket = bigbuckets[curr]; 
     std::sort(mybucket->begin(),mybucket->end(), [](const unsigned int& x, const unsigned int& y){ 
      std::string tmp1 = std::to_string(x); 
      std::string tmp2 = std::to_string(y); 
      return lexicographical_compare(tmp1.begin(), tmp1.end(), tmp2.begin(), tmp2.end()); 
      //return aLessB(x,y,0); 
     }); 
     ++curr; 
    } 
    }; 
// create a container of threads 
    containerOfThreads.clear(); 

    workload = 10/numCores; 
// create threads and add them to the container. 
    for (unsigned int i = 0; i < numCores; ++i) { 
    // start the thread. 
    unsigned int start = workload * i; 
    unsigned int end = workload * (i + 1); 
    if(i == numCores - 1) end = 10 ; 
    containerOfThreads.push_back(std::make_shared<std::thread>(sort_big_buckets, start, end)); 
    } 

// join all the threads back together. 
    for (auto t : containerOfThreads) t->join(); 
// put all elements back to numbersToSort 
    for (auto i = bigbuckets.begin(); i != bigbuckets.end(); ++i) { 
    numbersToSort.insert(numbersToSort.end(), (*i)->begin(), (*i)->end()); 
    } 
} 
+0

неродственных на ваш вопрос, но почему есть вектор (Я предполагаю) общих указателей на 'std :: thread'? Вы проезжаете этот вектор вокруг? Будете ли вы делать больше с потоками, чем просто присоединиться к ним? Почему не просто простой вектор объектов 'std :: thread'? Затем вы можете использовать 'emplace_back' для создания потоков. –

+0

Что касается вашей проблемы, что такое 'bigbuckets'? Что такое содержимое «bigbuckets»? Можете ли вы создать [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и показать нам? –

+0

@Someprogrammerdude Я не передаю вектор вокруг, и я использую его, потому что один из примеров моего учебника использует его. Я попробую метод, который вы упомянули, спасибо за совет! Также я отредактировал пример с тем, что я сделал, пытаясь подойти к сортировке. – SuperMurloc

ответ

2

Я не знаю, как реализовать этот бит в мой код, я не уверен, о том, что ведро [] делать в коде выше. Может ли кто-нибудь объяснить, какие изменения я должен внести?

Если быть честным, то ковши [] не нужны. Идея состоит в том, чтобы сохранить индексы начинаний ковша здесь, но так как более поздние ковши обрабатываются в одном порядке один за другим, вместо этого массива можно использовать пару дополнительных переменных.

Как я уже сказал, вам нужно преобразовать числа в строки и отсортировать строки. Таким образом, вы сможете проверить 1 символ на bucketing, не делая все операции create-string-> compare-> destroy-string. В итоге вам придется преобразовывать строки обратно в числа.

Часть кода вы спрашивали может выглядеть следующим образом:

void radixSort(std::vector<std::string>::iterator begin, std::vector<std::string>::iterator end, int digit){ 
    if (begin == end) 
     return; 

    // first skip short numbers 
    e = begin; 
    for (auto p = begin; p != end; ++p) 
     if (p->size() <= digit) 
     { 
      if (p != e) 
       std::swap(*p, *e); 
      q++; 
     } 
    if (e == end) 
     return; 

    for (char d = '0'; d <= '9'; ++d) 
    { 
     auto s = e; 
     for (auto p = e; p != end; ++p) 
      if (p->at(digit) == d) 
      { 
       if (p != e) 
        std::swap(*p, *e); 
       e++; 
      } 
     radixSort(s, e, digit+1); 
    } 
} 

Для сортировки строк вектора вы можете сделать что-то вроде этого:

radixSort(v.begin(), v.end(), 0); 
Смежные вопросы