【C++】矩阵翻转/n*n的矩阵旋转

刷题时被矩阵的旋转操作卡了n次了,决定写篇博客总结一下

思路参考:第40次CSP认证前四题 - Oaths - 博客园https://www.cnblogs.com/oaths/articles/19327767

这位大佬的实现个人感觉是比较符合直觉的(也比较好记)

翻转

矩阵坐标从(1,1)开始

翻转第x0到第x1行,第y0到第y1列的子矩阵,oi=1即上下翻转,oi=-1就左右翻转

cpp 复制代码
void fan_zhuan(int x0, int y0, int x1, int y1, int oi){
    if(oi == 1){ //上下翻转 
        while(x0 < x1){
            for(int i = y0; i <= y1; i ++ ){
                swap(a[x0][i], a[x1][i]); 
            }
            x0 ++ ; x1 -- ;
        }
    }
    else{//左右翻转
        while(y0 < y1){
            for(int i = x0; i <= x1; i ++ ){
                swap(a[i][y0], a[i][y1]);
            }
            y0 ++ ; y1 -- ;
        }
    }
}

旋转

注意:逆时针转i次90度==顺时针转4-i次90度;此处代码实现顺时针旋转

a为原矩阵,b为辅助矩阵,如果是旋转整个边长为l的正方形矩阵,公式为:

  • 顺时针转90度:bjl-i+1 = aij;
  • 顺时针转180度:bl-i+1l-j+1 = aij;
  • 顺时针转270度:bl-j+1i = aij;

只旋转左上角为(x,y),边长为l的l*l小矩阵,只需在a的下标加上偏移量,小矩阵第i行,即原矩阵的x+i-1行,小矩阵的第j列,即原矩阵的y+j-1行

  • 顺时针转90度:bjl-i+1 = ax+i-1y+j-1;
  • 顺时针转180度:bl-i+1l-j+1 = ax+i-1y+j-1;
  • 顺时针转270度:bl-j+1i = ax+i-1y+j-1;
cpp 复制代码
/*
左上角坐标(x,y), 边长l,顺时针旋转90度*t次
*/
void  xuan_zhuan(int x,int y,int l,int t) { //time 次数 
	char b[N][N]; //辅助矩阵,坐标从(1,1)开始 只存需要旋转的小矩阵 
	if(t==0) return; //旋转0次 
	if(t==1) //顺时针转90度 90*1
	    for (int i = 1; i <= l; i++) {
	        for (int j = 1; j <= l; j++) {
	            b[j][l-i+1] = a[x+i-1][y+j-1];
	        }
    }
	else if(t==2){ //顺时针转180度 90*2次  
	    for (int i = 1; i <= l; i++)
	        for (int j = 1; j <= l; j++) {
	            b[l-i+1][l-j+1] = a[x+i-1][y+j-1];
	        }    	
	}
	else if(t==3){//顺时针转270度 90*3次
	    for (int i = 1; i <= l; i++) 
	        for (int j = 1; j <= l; j++) {
	            b[l-j+1][i] = a[x+i-1][y+j-1];
	        }    			
	} 
    
    //复制回去 
//    for(int i = 1; i <= l ; i ++ )
//        for(int j = 1 ; j <= l; j ++ ){
//            a[x + i - 1][y + j - 1] = b[i][j];
//        }

//    常数优化:使用 memcpy 进行整行拷贝
    for (int i = 1; i <= l; i++) {
        memcpy(&a[x + i - 1][y], &b[i][1], l*sizeof(char)); //memcpy(目标地址, 源地址, 字节数)
    }
} 

测试代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=405;
char a[N][N]; //1~N行 1~ 列

int z; //正方形边长 

void print()
{
	for(int i=1;i<=z;i++){
		for(int j=1;j<=z;j++)
			cout<<a[i][j];
		cout<<endl;
	}
}

/*
翻转第x0到第x1行,第y0到第y1列的矩阵,oi=1即上下翻转,oi=-1就左右翻转 
*/
void fan_zhuan(int x0, int y0, int x1, int y1, int oi){
    if(oi == 1){ //上下翻转 
        while(x0 < x1){
            for(int i = y0; i <= y1; i ++ ){
                swap(a[x0][i], a[x1][i]); 
            }
            x0 ++ ; x1 -- ;
        }
    }
    else{//左右翻转
        while(y0 < y1){
            for(int i = x0; i <= x1; i ++ ){
                swap(a[i][y0], a[i][y1]);
            }
            y0 ++ ; y1 -- ;
        }
    }
    cout<<"======="<<endl; 
	print();
	cout<<"======="<<endl; 
}

/*
左上角坐标(x,y), 边长l,顺时针旋转90度*t次
*/
void  xuan_zhuan(int x,int y,int l,int t) { //time 顺时针转90度的次数 
	char b[l+5][l+5]; //辅助矩阵,坐标从(1,1)开始,只存需要旋转的小矩阵 
	if(t==0) return; //旋转0次 
	if(t==1) //顺时针转90度 90*1
	    for (int i = 1; i <= l; i++) {
	        for (int j = 1; j <= l; j++) {
	            b[j][l-i+1] = a[x+i-1][y+j-1];
	        }
    }
	else if(t==2){ //顺时针转180度 90*2次  
	    for (int i = 1; i <= l; i++)
	        for (int j = 1; j <= l; j++) {
	            b[l-i+1][l-j+1] = a[x+i-1][y+j-1];
	        }    	
	}
	else if(t==3){//顺时针转270度 90*3次
	    for (int i = 1; i <= l; i++) 
	        for (int j = 1; j <= l; j++) {
	            b[l-j+1][i] = a[x+i-1][y+j-1];
	        }    			
	} 
    
    //复制回去 
//    for(int i = 1; i <= l ; i ++ )
//        for(int j = 1 ; j <= l; j ++ ){
//            a[x + i - 1][y + j - 1] = b[i][j];
//        }

//    常数优化:使用 memcpy 进行整行拷贝
    for (int i = 1; i <= l; i++) {
        memcpy(&a[x + i - 1][y], &b[i][1], l*sizeof(char)); //memcpy(目标地址, 源地址, 字节数)
    }

	cout<<"======="<<endl; 
	print();
	cout<<"======="<<endl; 
} 

void solve()
{
	cin>>z;
	for(int i=1;i<=z;i++)
	{
		string s; cin>>s;
		for(int j=1;j<=z;j++)
			a[i][j]=s[j-1];		
	}
//	print();
	fan_zhuan(1,1,4,4,1); //上下翻转 
	fan_zhuan(1,1,4,4,-1); //左右翻转- 
	xuan_zhuan(1,1,3,1); //1 1 3 1 
}

int main()
{
	ios::sync_with_stdio(0),cin.tie(0);
	solve();
	return 0;
}
/*
4
ABCD
EFGH
IJKL
MNOP

*/ 
相关推荐
To_OC7 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
炸膛坦客8 小时前
单片机/C/C++八股:(二十六)IIC 专题(I²C)---- 上集
c语言·c++·单片机
旖-旎8 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC8 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
Henry Zhu1238 小时前
C++中的特殊成员函数与智能指针
c++
delishcomcn9 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹9 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术10 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
_wyt00111 小时前
多重背包问题详解
c++·背包dp