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

c++ merging more sorted subarray into one array

本文关键字:数组 一个 合并 c++ 排序      更新时间:2023-10-16

如何有效地将更多排序的子数组合并到一个数组中。(所以不需要创建相同大小的新阵列。)

我有一个数组:

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}

您可以使用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个具有CCD_ 2的线程中的2个将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/pallel/quicksort.h

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

许多标准模板库都用于执行几个功能,Quicksort就是其中之一。当你调用std::sort时,很可能你调用的是看起来像的东西

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。如果根据线程数将分区的范围划分为大小相等的块,则最终会得到部分排序的范围——所有返回true到谓词的元素都将在返回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); 
    }    
}; 

使用CCD_ 7对于大的块/其中CCD_。在这种情况下,最好使用std::reverse(记住孩子们,如果你想要一个稳定的swap_block,你需要3个std::reverses!)

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

我在这里写了一个版本的parallel_partition。

相关文章: