(m,n)给定矩阵表示为单个大小数组,是否可以就地转置矩阵m*n?
(m,n)
m*n
常用算法
transpose(Matrix mat,int rows, int cols ){ //construction step Matrix tmat; for(int i=0;i<rows;i++){ for(int j=0;j<cols;j++){ tmat[j][i] = mat[i][j]; } } }
除非矩阵是方形矩阵,否则不适用于单个数组。如果没有,则最少需要多少额外的内存?
编辑:我已经尝试了所有口味
for(int i=0;i<n;++i) { for(int j=0;j<i;++j) { var swap = m[i][j]; m[i][j] = m[j][i]; m[j][i] = swap; } }
这是不正确的。在此特定示例中,m甚至不存在。在单行矩阵中mat[i][j] = mat[i*m + j],trans[j][i] = trans[i*n + j]
m
mat[i][j] = mat[i*m + j]
trans[j][i] = trans[i*n + j]
受到Wikipedia的启发-在循环算法描述之后,我想到了以下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
以行优先顺序表示 {0, 1, 2, 3, 4, 5, 6, 7}为4×2矩阵
{0, 1, 2, 3, 4, 5, 6, 7}
0 4 1 5 2 6 3 7
由行优先的order表示{0, 4, 1, 5, 2, 6, 3, 7}。
{0, 4, 1, 5, 2, 6, 3, 7}
该参数m的transpose代表ROWSIZE,所述columnsize n由ROWSIZE和序列大小来确定。该算法需要辅助存储的m× n位来存储信息,这些信息已被交换。序列的索引按以下方案映射:
transpose
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。该过程将继续该循环,直到所有循环都已转置为止。
{ 0 }
{ 1, 2, 4 }
{3, 5, 6}
{ 7 }
cycle
0 → 0
visited