c ++将更多排序的子数组合并到一个数组中

时间:2015-11-10 14:50:15

标签: c++ arrays sorting

如何有效地将更多排序的子数组合并到一个数组中。 (因此无法创建具有相同大小的新阵列。)

我有阵列:

int LENGHT = 12;
int ARRAY[LENGHT] = {5,8,6,3,48,65,1,8,9,20,21,57};

例如第四个线程中的冒泡排序:

int ARRAY[LENGHT] = {5,8,6,3,48,65,1,8,9,20,57,21};
thread_1 -> BubbleSort(0, LENGTH/4, ARRAY);
thread_2 -> BubbleSort(LENGTH/4, LENGTH/2, ARRAY);
thread_3 -> BubbleSort(LENGTH/2, (3*LENGTH)/4, ARRAY);
thread_4 -> BubbleSort((3*LENGTH)/4, LENGTH, ARRAY);

我明白了:

ARRAY[] = {3,5,6,  1,8,8,  9,45,65,  20,21,57};

合并到一个阵列的最佳方法是什么?

{3,5,6,  1,8,8,  9,45,65,  20,21,57} -> {1,3,5,  6,8,8,  9,20,21,  45,57,65}

2 个答案:

答案 0 :(得分:0)

你可以使用std::inplace_merge,像这样(c ++ 11):

#include <algorithm>
#include <iostream>
#include <iterator>

template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];

#define ARRAY_LEN(arr) (sizeof(ArraySizeHelper(arr)))

int main()
{
    int ARRAY[] = {3,5,6,  1,8,8,  9,45,65,  20,21,57};
    const size_t SORTED_CHUNK_SIZE = 3;
    for (size_t i = SORTED_CHUNK_SIZE; i < ARRAY_LEN(ARRAY); i += SORTED_CHUNK_SIZE) {
        auto beg = std::begin(ARRAY);
        auto mid = beg + i;
        auto end = mid + SORTED_CHUNK_SIZE;
        std::inplace_merge(beg, mid, end);
    }
    std::copy(std::begin(ARRAY),
          std::end(ARRAY),
          std::ostream_iterator<int>(std::cout,",")
        );
    std::cout << "\n";

}

<强>更新

如果你使用线程,你可以使用这样的策略: 假设您有4个线程,4个线程排序4个数组, 然后这4个线程中的2个std::inplace_merge将4个块合并为2个块, 然后这4个线程中的1个将这两个块合并为1。

另见这里: http://en.cppreference.com/w/cpp/experimental/parallelism/existing#inplace_merge

和实施https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/parallel/quicksort.h

答案 1 :(得分:0)

如果必须使用所有可能的硬件线程以最快的速度对数组进行排序,那么您需要创建一个可以使用多个线程的快速排序。

许多标准模板库都可以执行一些功能,Quicksort就是其中之一。当你打电话给std::sort时,你很可能会打电话给:{/ p>

template <class ForwardIt>
void sort(ForwardIt first, ForwardIt last)
{
    if (first == last) return;
    auto pivot = *std::next(first, std::distance(first,last)/2);
    ForwardIt middle1 = std::partition(first, last, 
                         [&pivot](const auto& em){ return em < pivot; });
    ForwardIt middle2 = std::partition(middle1, last, 
                         [&pivot](const auto& em){ return !(pivot < em); });
    sort(first, middle1);
    sort(middle2, last);
 }

(归功于en.cppreference)

这里的主要功能是std::partition。如果根据线程数将分区范围划分为相等大小的块,则最终会得到部分排序范围 - 所有返回谓词的元素都将在返回false的元素之前。它也至关重要地返回该元素的迭代器 - 在上面的例子中有用地称为middle

通过将这些返回的迭代器存储在一个数组中,您可以

for (auto i=n-2; i>0; --i) 
{ 
    auto begin = r[i]; 
    auto mid = std::next(first, b * (i + 1)); 
    auto end = last; 
    swap_block<Iter>()(begin, mid, last); 
} 
swap_block<Iter>()(r[0], std::next(first, b), last); 

swap_block的样子:

template<typename Iter> 
struct swap_block 
{ 
    void operator()(Iter first, Iter mid, Iter last) 
    {
        std::rotate(first, mid, last); 
    }    
}; 

使用std::rotate对于大块/那些mid朝向范围末尾的块来说效率非常低。在这些情况下,最好使用std::reverse(并记住孩子,如果你想要一个稳定的swap_block你需要3 std::reverse!)

TL; DR:学习如何有效地使用STL算法库。

我编写了一个版本的parallel_partition here