两种蛇形矩阵

在经历了无数个大坑,一步步调整,这玩意对初学者太不友好了,不过它可以提高你对于矩阵的理解,快速掌握二位数组!

今天主要说两种形式的矩阵:

第一种:绕圈型蛇形矩阵

样例如下:

1        2        3        4

 12     13     14       5

 11      16     15       6

 10      9        8        7

这种数组的写法比较奇特,在看了网上很多教程之后我感觉还是较为繁杂,因此我建议小白可以学习一下这种写法,很方便,记下来就好。代码如下,会附赠讲解

#include <iostream>
using namespace std;
int main() {
    int a[100][100];
    int x = 1, y = 0, k = 1;
    int n;
    cin >> n;
    while (k <= n * n) {
        ;
        while (y < n && !a[x][y + 1]) a[x][++y] = k++;
        while (x < n && !a[x + 1][y]) a[++x][y] = k++;
        while (y > 1 && !a[x][y - 1]) a[x][--y] = k++;
        while (x > 1 && !a[x - 1][y]) a[--x][y] = k++;
        
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            printf("%5d", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

        这个的思路就是,一圈一圈的去思考,但我们并不是一圈一圈来写循环。

外面套个while保证次数和k的大小有关,不过请注意,这里的k是要小于等于。

        内层的话,我来解释几个地方:

!a[x][y + 1]的意思就等同于a[x][y + 1] == 0 用来判断下一位是不是为空

注意也要分清楚++y和y++之间的区别,我们是站在一个点去看待下一个点的数值

a[x][++y] is equal to y++; a[x][y] = k; k++;


        那么有人会问了,你这是逆时针的方向,我偏要写顺时针的方向那咋整;

你只需要改一下初始条件: x  =  0, y = 1;循环体里面把第二个和第一个调换第四个和第三个调换就可以了,这样就ok了;

        最后提醒一句,这个写法容易死循环(主要是我手欠写错条件,嘿嘿警示你们了哈, 写代码一定要走心啊

question 2

接下来我们便请出第二位重量级选手:拐弯蛇形矩阵(貌似第一个也拐弯。。orz

输出样例

     1    2    6    7
    3    5    8   13
    4    9   12   14
   10   11   15   16

这个数组着实花费了我不少时间,目前我也没想出来更好的解决方法,主要是找不到数学规律

代码如下,稍后讲解:


#include <iostream>
using namespace std;
int main() {
    int n, m, i, j, k = 1, h;
    cin >> n;
    int a[120][100];
    for (i = 1; i <= n; i++) {
        j = i + 1;
        if (i % 2) { //jishu
            for (h = 1; h <= i; h++) {
                a[j - h][h] = k++;
            }
        } else {
            for (h = 1; h <= i; h++) {
                a[h][j - h] = k++;
            }
        }
    }
    for (; i <= n * 2 - 1; i++) {
        j = i + 1;
        if (i % 2) { //jishu:    
            for (h = n; h >= i - n + 1; h--) {
                a[h][j - h] = k++;
            }
        } else {
            for (h = n; h >= i - n + 1; h--) {
                a[j - h][h] = k++;
            }
        }
    }
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= n; j++) {
            printf("%5d", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

这个问题最重要的就是找到每一斜行的循环起点表示方法,以及循环次数!!!!!!

开始漫长的讲解:

        这个题目我的思路是这样的,斜着去看待每一排,也就是说这样的一排下标数之和是相等的,我们只需要找到起始条件就可以了。

        首先我们知道一共有 2 * n - 1个斜行,首先我们要去判断第一行到第n行 ,为什么我们要先判断1到n呢 ? 因为他们的起始位置在 (1   ,  x ) 或者是 (x,1)这样的位置,而到了 n + 1 以后的位置起始点就是(n, x)或者是 (x, n)。

        我们先分析1到n(其实第n行也可以放到后面进行处理,反正为了方便我写了两个大循环)

从1到n每一斜行下标之和为 j = i + 1;判断i是奇数还是偶数,如果是奇数就先从左下角开始循环,如果是偶数,就在右上角开始循环。每一个循环循环的次数就等于i值。

这样就写出来了

j = i + 1;
        if (i % 2) { //jishu
            for (h = 1; h <= i; h++) {
                a[j - h][h] = k++;
            }
        } else {
            for (h = 1; h <= i; h++) {
                a[h][j - h] = k++;
            }
        }

对于 n + 1 到2 * n - 1的循环我费了不少时间,没有找到正确思路吧,主要是考虑起始点和循环次数的问题

这一部分循环不等同于前面的循环,是从n开始减少

 if (i % 2) { //jishu:    
            for (h = n; h >= i - n + 1; h--) {
                a[h][j - h] = k++;
            }
        } else {
            for (h = n; h >= i - n + 1; h--) {
                a[j - h][h] = k++;
            }
        }

还是老样子,如果掉头的方向发生了变化就把奇数部分和偶数部分换过来就OK了

最后,祝福每一个写代码的朋友吧,生活不易,看完了点个赞再走吧, 要是能加个关注就更好了,嘻嘻,谢了,时间不早了,快两点了,早休息啊!