vb 实现二维数组(矩阵)转置。_矩阵的旋转与转置(inplace)

博客探讨了在不使用额外内存的情况下,如何进行二维数组(矩阵)的原地转置操作,以及方形矩阵的原地旋转90度问题。通过分析规律和循环,实现了高效的数据转换。此外,分享了工作中实际应用算法的重要性,并引用了相关博客资源作为代码参考。
摘要由CSDN通过智能技术生成

最近实现tensorflow模型转换为caffe前向计算的时候存在一个数据维度的问题,即tf的数据格式一般习惯把channel放在最后一维,caffe一般放在第一维;即将一个dxc的二维矩阵转置成为cxd;如何不需要额外内存的情况下,完成这一操作;

具体如图所示:

c57f6b6af9d765a0c3a6f16e366e31c6.png

可以按照上图找一下规律,发现:

6b54f832f96d089c4cdf84cdbbf22c82.png

可以发现,数据的移动可以演变为一个循坏;遍历完每个“环”,那么任务就完成了;

循环过程需要找到后继节点;

int getNext(int i, int m, int n)  //m为转置后的行数,n为转置后的列数
{  
    return (i%n)*m + i/n;  
}  

填补的时候需要找到前驱节点;

int getPre(int i, int m, int n) // m为转置后的行数,n为转置后的列数 
{  
    return (i%m)*n + i/m;   
} 

遍历数组,判断当前节点是否为所在环的初始点,初始点的定义为:环中节点在数组(一维)中的index 最小值,例如上图中的1号节点;

void transpose(int *mtx, int m, int n)  
{  
	for(int i=0; i<m*n; ++i)  
	{  
		int next = getNext(i, m, n);  
		while(next > i) // 若存在后继小于i说明已经出现之前的环中;
			next = getNext(next, m, n);  
		if(next == i)   // 当前节点i就是环的初始节点,处理当前环   
			movedata(mtx, i, m, n);  
	}  
}

下面开始处理该环的赋值操作,赋值是由前驱节点的值赋值到当前节点所在的位置:

void movedata(int *mtx, int i, int m, int n)  
{  
	int temp = mtx[i];  // 备份  
	int cur = i;       // 当前下标  
	int pre = getPre(cur, m, n);  
	while(pre != i)  
	{  
		mtx[cur] = mtx[pre];  
		cur = pre;  
		pre = getPre(cur, m, n);  
	}  
	mtx[cur] = temp;  
} 

以上是关于任意二维矩阵的原地转置操作,下面介绍方形矩阵的原地旋转90度操作,是leetcode中的一道中等难度的一道题;

力扣​leetcode-cn.com
class Solution {
public:
    void swap(int& i, int& j)
    {
        int temp = i;
        i = j;
        j = temp;
        return;
    }
    void rotate(vector<vector<int>>& matrix) 
    {
        int n = matrix.size();

        for(int i = 0; i < n/2; ++i)
        {
            for(int j = 0; j < n/2; ++j)
            {
                swap(matrix[i][j], matrix[j][n-1-i]);
                swap(matrix[i][j], matrix[n-1-i][n-1-j]);
                swap(matrix[i][j], matrix[n-1-j][i]);
            }
        }
        
        if(n%2==1)
        {
            for(int i = 0; i < n/2+1; ++i)
            {
                swap(matrix[i][n/2], matrix[n/2][n-1-i]);
                swap(matrix[i][n/2], matrix[n-1-i][n-1-n/2]);
                swap(matrix[i][n/2], matrix[n-1-n/2][i]);
            }
        }
        return;
    }
};

分成奇数和偶数两种情况分别考虑,逻辑更加清晰;

与之前的转置有异曲同工之妙在于 也是一组 四个位置的数字循环,不过这里的“环”坐标之间存在对应关系;

[i][j]--->[j][n-1-i]---->[n-1-i][n-1-j]---->[n-1-j][i]

可以看出:后驱节点的行数等于前驱节点的列数,后驱节点的列数等于前驱节点的(n-1-行数);


该博客主要作用在于工作中的记录;之前认为的所有的算法题都是无中生有。真正用到的时候还是真香!!!其中:

原地矩阵转置的代码参考博客:

矩阵--原地转置--面试题_网络_戎码人生-CSDN博客

原地方形矩阵的旋转是我在leetcode上的实现;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值