由Wikipedia - Following the cycles算法描述的啓發,我提出了以下C++實現:
#include <iostream> // std::cout
#include <iterator> // std::ostream_iterator
#include <algorithm> // std::swap (until C++11)
#include <vector>
template<class RandomIterator>
void transpose(RandomIterator first, RandomIterator last, int m)
{
const int mn1 = (last - first - 1);
const int n = (last - first)/m;
std::vector<bool> visited(last - first);
RandomIterator cycle = first;
while (++cycle != last) {
if (visited[cycle - first])
continue;
int a = cycle - first;
do {
a = a == mn1 ? mn1 : (n * a) % mn1;
std::swap(*(first + a), *cycle);
visited[a] = true;
} while ((first + a) != cycle);
}
}
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
transpose(a, a + 8, 4);
std::copy(a, a + 8, std::ostream_iterator<int>(std::cout, " "));
}
該程序使2×4矩陣
0 1 2 3
4 5 6 7
的就地矩陣轉代表row-major ordering{0, 1, 2, 3, 4, 5, 6, 7}
進4×2矩陣
0 4
1 5
2 6
3 7
由行主排序{0, 4, 1, 5, 2, 6, 3, 7}
表示。
transpose
的參數m
代表行大小,列大小由行大小和序列大小決定。該算法需要m
×n
位的輔助存儲來存儲信息,哪些元素已被交換。序列的索引映射下列方案:
0 → 0
1 → 2
2 → 4
3 → 6
4 → 1
5 → 3
6 → 5
7 → 7
在一般的映射函數爲:
IDX→(IDX×n)個MOD(m×n個 - 1)如果IDX < (M×N),IDX→IDX否則
我們可以確定該序列內的四個週期:{ 0 }
,{ 1, 2, 4 }
,{3, 5, 6}
和{ 7 }
。每個週期可獨立於其他週期進行調換。變量cycle
最初指向第二個元素(第一個不需要移動,因爲0 → 0
)。位陣列visited
保存已經轉置的元素並且指示需要移動索引1(第二元素)。索引1與索引2(映射函數)交換。現在,索引1包含索引2的元素,並且此元素與索引4的元素交換。現在索引1包含索引4的元素。索引4的元素應該轉到索引1,它位於正確的位置,轉置的週期已經完成,所有被觸摸的索引都被標記爲已訪問。變量cycle
獲得增加,直到第一個未訪問的索引爲3,該過程繼續進行,直到所有的循環都轉換完畢。
這是可能的,但不平凡。像往常一樣,維基百科有答案。 http://en.wikipedia.org/wiki/In-place_matrix_transposition – harold 2012-02-10 12:33:28
[前一段時間,我問了一個類似的問題,而不知道正確的術語](http://stackoverflow.com/q/3009379/237483) – 2012-02-10 12:49:17
感謝Harold!我將制定一個實施並在此處發佈。 – UmNyobe 2012-02-10 12:49:54