【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度:b[j][l-i+1] = a[i][j];
  • 顺时针转180度:b[l-i+1][l-j+1] = a[i][j];
  • 顺时针转270度:b[l-j+1][i] = a[i][j];

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

  • 顺时针转90度:b[j][l-i+1] = a[x+i-1][y+j-1];
  • 顺时针转180度:b[l-i+1][l-j+1] = a[x+i-1][y+j-1];
  • 顺时针转270度:b[l-j+1][i] = a[x+i-1][y+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

*/ 
相关推荐
sycmancia1 小时前
C++——类的真正形态、构造函数的调用
开发语言·c++
m0_531237171 小时前
C语言-指针,结构体
c语言·数据结构·算法
癫狂的兔子2 小时前
【Python】【机器学习】十大算法简介与应用
python·算法·机器学习
丰海洋2 小时前
leetcode-hot100-1.两数之和
数据结构·算法·leetcode
苦藤新鸡2 小时前
58 单词搜索
数据结构·算法
CHANG_THE_WORLD2 小时前
C/C++字符串定义的五种写法 和 C/C++字符串隐藏技术深度剖析
c++
_F_y2 小时前
背包问题动态规划
算法·动态规划
Frostnova丶2 小时前
LeetCode 401. 二进制手表
算法·leetcode
sycmancia2 小时前
C++——初始化列表的使用
开发语言·c++