矩阵的螺旋输出:[Python][C]实现

版权声明:
  如要转载,请与我联系。


1. 问题概述

给定一个M*N(M行,N列)的矩阵,以螺旋的顺序返回矩阵所有元素。

本文以顺时针螺旋为例。 😄

关键词:二维数组、螺旋输出、遍历


2. 思路构建

最近在做CCFCSP。但是CCFCSP上没有这个题,所以这个题是我虚构的。

CCFCSP的题目通常会给出 m m m n n n的大小;

然后依次输入 m × n m×n m×n二维数组的元素。

补充:假设 0 < m < n < 100 0<m<n<100 0<m<n<100

例如

说明输入输出
第1行3 31 2 3 6 9 8 7 4 5
第2行1 2 3
第3行4 5 6
第4行7 8 9

3. 程序实现

下面两种方法,方法一是Python实现,方法二是C语言实现。两种语言用的方法不一样,请家人们自行选择观看。


3.1 方法一

按照矩阵的“厚度”循环。

即第t次循环以t,t为起点以(t+1,t)为终点画圈,直到将Matrix螺旋遍历完毕;

这种方式理解起来非常简单,社区里很多人都写。

这里不多做赘述,下面直接放python实现的代码。

注:Python接收的是一个二维列表

'''

    @author:Lyn#reo
    @create:2020.10.13
	#可以根据需要修改
    #如有二次发送的必要
    #请留下修改者和修改日期:)
    #感激您的真诚#
'''
def SpiralOrder():
    d=0
    List=[]
    while 2*d<LenM and 2*d<LenN:
        for j in range(d,LenN-d):
            List.append(matrix[d][j])
        for i in range(d+1,LenM-d):
            List.append(matrix[i][LenN-1-d])
        if LenM-2*d!=1:    
            for j in range(LenN-d-2,d-1,-1):
                List.append(matrix[LenM-1-d][j])
        if LenN-2*d!=1:    
            for i in range(LenM-d-2,d,-1):
                List.append(matrix[i][d])
        d+=1   
    return List

matrix=eval(input())
if matrix!=[]:
    LenN=len(matrix[0])
    LenM=len(matrix)
    res=SpiralOrder()
    print(res)
else:
    print([])

3.2 方法二

重点来说说方法二

画出数组的“地图”,若碰到地图的“边界”已遍历过的“区域”,就改变“方向”。遍历结束后退出程序即可;

敲黑板!!!这几个词下面要考


3.2.1 发现

顺时针旋转的呈现出规律性

向右遍历、向下遍历、向左遍历、向上遍历、向右遍历…

如此往复,如下图

就如同我们贴左侧墙开车,一直右转

因此只需将遍历索引写成顺序右转的即可。


3.2.2 关键准备工作

写程序就如同炒菜,要做一些准备 😄

struct Direction{
    int i,j;
}Go[4]={{0,1},{1,0},{0,-1},{-1,0}};D
/*定义一个结构体储存行径的方向*/

int t=0;
/*以及一个全局变量作为行径方向的索引,用t++和t%4的方式可以让行径方向循环*/

char map[N][N];
/*地图用来记录边界条件和已访问过的位置*/

int Element[N][N];
/*二维数组矩阵用来储存题目给出的二维数组*/

3.2.3 核心算法


通过索引进入矩阵,首先要将矩阵的当前值带出来;

其次,既然已经读取了,就要在地图上记录访问过该点了

将两句伪代码打包写成一个函数

void OutTunnelsOrder(int x,int y)
{
    printf("%d",Element[x][y]);
    printf(" ");
    map[x][y]='#';//留下位置
}

显然,我们还要进行判断

判断下个要去的矩阵点是否可进入。

如果不能进入要调整行径方向的索引。

int JadgeDextroversion(int x,int y)//对坐标进行判断
{
    if(map[x][y]=='#')
    {
        t++;//调整坐标索引
        return 0;
    }
    return 1;
}

很容易得知,需要进行两次判断。

  1. 判断下一次的索引坐标是否可以走。若可走,则将索引坐标赋给next;若不可走,根据判断程序会更改坐标索引(t++),再将索引坐标赋给next;
  2. 判断被赋值的next,若可走,则进行next坐标的读取;若不可走,则说明已经遍历完毕了,得退出程序。
void SpiralOrder(int x,int y)
{
    JadgeDextroversion(x+Go[t%4].i,y+Go[t%4].j);
    //判断下一次的索引坐标
    OutTunnelsOrder(x,y);
    nextx=x+Go[t%4].i;
    nexty=y+Go[t%4].j;
    if(JadgeDextroversion(nextx,nexty))
    //判断被赋值的next
    {
        SpiralOrder(nextx,nexty);//递归进行下一个坐标
    }
    else
    {
        exit(0);
    }
}

3.2.4 完整程序

/*
    filename:MatrixSpiral.c
    author:Lyn#reo
    create:2020.10.18
    #可以根据需要修改
    #如有二次发送的必要
    #请留下修改者和修改日期:)
    #感激您的真诚#
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 102
/*定义一个结构体储存行径的方向*/
struct Direction{
    int i,j;
}Go[4]={{0,1},{1,0},{0,-1},{-1,0}};

/*以及一个全局变量作为行径方向的索引*/
int t=0;

int nextx,nexty;
char map[N][N];
int Element[N][N];

int JadgeDextroversion(int x,int y)//对坐标进行判断
{
    if(map[x][y]=='#')
    {
        t++;//调整坐标索引
        return 0;
    }
    return 1;
}

void OutTunnelsOrder(int x,int y)
{
    printf("%d",Element[x][y]);//输出指令
    printf(" ");
    map[x][y]='#';//留下标记
}

void SpiralOrder(int x,int y)
{
    JadgeDextroversion(x+Go[t%4].i,y+Go[t%4].j);
    //判断下一次的索引坐标
    OutTunnelsOrder(x,y);
    nextx=x+Go[t%4].i;
    nexty=y+Go[t%4].j;
    if(JadgeDextroversion(nextx,nexty))
    //判断被赋值的next
    {
        SpiralOrder(nextx,nexty);//递归进行下一个坐标
    }
    else
    {
        exit(0);
    }
}

int main()
{
    memset(map,'#',sizeof(map));
    memset(Element,0,sizeof(Element));

    int m,n;
    scanf("%d%d",&m,&n);
    int i,j;
    for(i=1;i<m+1;i++)
    {
        for(j=1;j<n+1;j++)
        {
            scanf("%d",&Element[i][j]);
            map[i][j]='\0';
        }
    }
    SpiralOrder(1,1);//从(1,1)进入
    return 0;
}

4 写在最后

文案、代码、制作:Lyn#reo

由于写Python题的时候,算遍历的边界坐标让我算的头疼,所以我想写个不用坐标来管边界的程序,但我又不会写Python的实现方法,于是本文就诞生了。

本文只是以顺时针为例,逆时针只需要改变Go中储存位置的顺序就好了。

思路受启发于CCFCSP2013-5的用DFS“画地图”思路,并不是真正意义上的DFS

它的缺点是空间占用要多使用 ( 4 n + 4 ) (4n+4) (4n+4)的空间

介绍地比较深入,仔细看时方便理解,如果觉得我写的不错,还请为我点个免费的赞!

祝你变得更强,下次见 😃

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值