В этой статье «Простой алгоритм замены на месте» описывает, как транспонировать матрицу из 2 * N, и дает подсказку, как это сделать для других случаев, поэтому 3 * N может быть также возможно. Этот ответ на другой вопрос показывает, что это действительно возможно.
Или используйте алгоритм, который записывает каждое значение в его транспонированное место, затем делает то же самое для значения из этого места и так далее, пока цикл не будет связан. Пометить обработанные значения в битовом векторе. И продолжайте, пока этот вектор не станет равным 1 с.
Оба алгоритма не подходят для кэширования. Возможно, какое-нибудь умное использование инструкции PREFETCH может улучшить это.
Edit:
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 и поместите индексы в очередь (кольцевой буфер), затем получите индексы из очереди и переместите данные.
Edit3:
Идея другого алгоритма, который имеет размер O (1), время O (N * log (N)), является кеш-памятью и может быть быстрее, чем алгоритм "цикла" (для размеров изображения <1 Гб): </p>
- Разделить матрицу N * 3 на несколько 3 * 3 матриц char и транспонировать их
- Разделите результат на 3 * 3 матрицы char [3] и транспонируйте их
- Продолжить, пока размер матрицы меньше размера массива
- Теперь у нас есть до 3 * 2 * log3 (N) заказанных частей. Присоединяйтесь к ним.
- Первые соединительные фигуры одинакового размера. Можно использовать очень простые «циклы» длины 4.
- Соединение деталей неравного размера с реверсом (реверс (а), реверс (б))