本文“In-Shuffle的简单就地算法”描述了如何转置2 * N的矩阵并给出了如何在其他情况下进行的提示,因此3 * N也是可能的。 这个对其他问题的回答表明它确实是可能的。
或者使用将每个值写入其转置位置的算法,然后对该位置的值执行相同的操作,依此类推,直到连接循环。 在位向量中标记处理的值。 并继续,直到这个向量全是1。
这两种算法都不是缓存友好的。 可能一些巧妙使用PREFETCH指令可以改善这一点。
编辑:
C ++,RGB到单平面,未优化:
#include <iostream>
#include <bitset>
#include <vector>
enum {N = 8};
void transpose(std::vector<char>& a)
{
std::bitset<3*N> b;
for (int i = 1; i < 3*N; ++i)
{
if (b[i])
continue;
int ptr = i;
int next;
char nextVal = a[i];
do {
next = ptr/3 + N*(ptr%3);
char prevVal = nextVal;
nextVal = a[next];
a[next] = prevVal;
ptr = next;
b[ptr] = true;
}
while (ptr != i);
}
}
int main()
{
std::vector<char> a(3*N);
for (int i = 0; i != 3*N; ++i)
a[i] = i;
transpose(a);
for (int i = 0; i != 3*N; ++i)
std::cout << (int)a[i] << std::endl;
return 0;
}
我的初衷是使用大小为WIDTH HEIGHT的位向量,这会产生WIDTH HEIGHT / 8的开销 。 但是总是有可能牺牲空间的速度。 位向量可以是大小WIDTH或HEIGHT或任何期望值,甚至是0.技巧是保持指向单元的指针,在此之前所有值都被转置。 位向量用于从该指针开始的单元格。 在全部为1之后,将其移动到下一个位置,然后执行除实际数据移动之外的所有算法步骤。 并且位向量已准备好继续转置。 该变体是O(N ^ 2)而不是O(N)。
EDIT2:
PREFITCH优化并不难实现:只需计算索引,调用PREFETCH,并将索引放入队列(ringbuffer),然后从队列中获取索引并移动数据。
EDIT3:
其他算法的概念,即O(1)大小,O(N * log(N))时间,是缓存友好的并且可能比“循环”算法更快(对于图像大小<1Gb):
- 将N * 3矩阵拆分为几个3 * 3的char矩阵并转置它们
- 将结果拆分为char [3]的3 * 3矩阵并转置它们
- 矩阵大小小于数组大小时继续
- 现在我们有最多3 * 2 * log3(N)的订购件。 加入他们。
- 首先加入相同尺寸的件。 可以使用长度为4的非常简单的“循环”。
- 用反向加入不等大小的碎片(反向(a),反向(b))