通过迭代旋转重新排序算法

时间:2017-02-05 01:20:59

标签: c++ algorithm asymptotic-complexity

考虑包含N个样本的数据集,其中每个样本都包含head个元素,后跟tail个元素。我想执行稳定的重新排序,以便N tails在顶部组合在一起,N heads在底部组合在一起。

例如,数据集:

 -1  -2  -3   1   2   3   4   5
 -4  -5  -6   6   7   8   9  10
 -7  -8  -9  11  12  13  14  15
-10 -11 -12  16  17  18  19  20

N = 4个样本,head = 3(负整数)和tail = 5(正整数)。期望的转变将产生:

  1   2   3   4   5   6   7   8
  9  10  11  12  13  14  15  16
 17  18  19  20  -1  -2  -3  -4
 -5  -6  -7  -8  -9 -10 -11 -12

我实施了一个基于重复旋转应用的解决方案。轮换是由C ++算法std::rotate实现的:

  

std::rotate(first, n_first, last)交换范围内的元素   [first, last)以元素n_first成为的方式n_first - 1   新范围的第一个元素和N成为最后一个元素   元件。

我的实施(如下所示)提供了正确的解决方案,并且可以很好地解决我的问题。但是,它需要执行O(head + tail)轮换,每次轮换的复杂度从O(N * tail + head)增加到#include <algorithm> #include <vector> #include <iostream> #include <iomanip> template <typename I> // I models Forward Iterator I reorder(I f, I l, std::size_t head_size, std::size_t tail_size) { std::size_t k = 1; auto m = std::next(f, head_size); auto t = std::next(m, tail_size); while (t != l) { f = std::rotate(f, m, std::next(m, tail_size)); m = std::next(f, ++k * head_size); t = std::next(m, tail_size); }; return std::rotate(f, m, t); } template <typename C> void show(const char* message, const C& c) { std::size_t shown { 0 }; std::cout << message << "\n"; for (auto && ci : c) std::cout << std::setw(3) << ci << (++shown % 8 == 0 ? "\n" : " "); } int main() { std::vector<int> v { -1, -2, -3, 1, 2, 3, 4, 5, -4, -5, -6, 6, 7, 8, 9, 10, -7, -8, -9, 11, 12, 13, 14, 15, -10, -11, -12, 16, 17, 18, 19, 20 }; std::size_t head_size { 3 }; std::size_t tail_size { 5 }; show("before reorder", v); reorder(v.begin(), v.end(), head_size, tail_size); show("after reorder", v); return 0; }

您是否了解具有更高复杂度的算法?

我的代码如下:

$ clang++ example.cpp -std=c++14
before reorder
 -1  -2  -3   1   2   3   4   5
 -4  -5  -6   6   7   8   9  10
 -7  -8  -9  11  12  13  14  15
-10 -11 -12  16  17  18  19  20
after reorder
  1   2   3   4   5   6   7   8
  9  10  11  12  13  14  15  16
 17  18  19  20  -1  -2  -3  -4
 -5  -6  -7  -8  -9 -10 -11 -12

编译并运行:

[metadata] [pixels...]
[metadata] [pixels...]
[ many more of these]
[metadata] [pixels...]

有关问题域的详细信息

我正在阅读每个前面都有像素元数据的图像,然后是原始像素,如下所示:

 [all the pixels] [all the metadata]

我需要将所有像素打包在一起并将它们传递给OpenGL,但我还需要维护程序可访问的元数据。所以,我这样做:

[all the pixels]

并将[all the metadata]传递给我的显卡,同时保留CPU中" "的句柄。

修改

感谢您的回复 - 我最终实施了一个不依赖于重新排序的替代解决方案。但是,重点仍然是:您是否可以改进“就地”数据集重新排序的算法?它类似于就地矩阵转置

2 个答案:

答案 0 :(得分:2)

一个非常快速的解决方案是创建另一个矩阵并将元素直接放在它们所属的位置。

例如,假设你有n行,t行和h头。第一行(1,1)上的第一个尾部将进入((h * n + 1)/(h + t),(h * n + 1)%(h + t))。我会让你为一般情况(i,j)制定去(k,l)。在任何情况下,它都是涉及整数除法和模数的计算。

答案 1 :(得分:1)

从输入格式开始:

[metadata] [pixels...]
[metadata] [pixels...]
[ many more of these]
[metadata] [pixels...]

你应该做的是将这些直接读到你需要的结构中,据我所知,这是两个:连续的像素和连续的元数据。所以:

std::vector<Pixel> pixels;
std::vector<Metadata> meta;
// maybe reserve() a reasonable amount based on input size

// for each record in input:
    pixels.push_back(...);
    meta.push_back(...);

现在你有一个向量,所有像素数据都传递给GPU,还有一个带有你自己的所有元数据。无需复制内存。