如何有效地将更多排序的子数组合并到一个数组中。 (因此无法创建具有相同大小的新阵列。)
我有阵列:
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}
答案 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。