回形矩阵
首先我们来看个问题:
上面这个n*n的回形矩阵要怎么在程序中输出呢?我们仔细看不难看出数字都像一个海螺一样内旋增大,也就是有一定规律。但要是n一直变大,我们要怎样确定这些数字的位置呢?
下面是我的解决方法:
首先我创建了一个二维数组,用于存放这些数据,到时候打印只需要将这些数一个个打印出来就行了,我们先从简单做起,先创建一个数组并且写好输出的代码,毕竟凡事从简单做起嘛!
int main()
{
int n = 0;
scanf("%d", &n);
int arr[19][19] = { 0 };
//....
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
printf("%-1d ", arr[i][j]);
printf("\n");
}
return 0;
}
然后就是要考虑怎么按顺序将这些数字排进去的问题了,我的思路是这样的:
我们将数据按这样螺旋着排放,首先将数据从左向右排放,直至右边触碰到边界,再调头向下输入数据,然后向左,再向上输入数据。然后重新向右输入.....以此循环直至将n*n输入到数组中。
#define CONDITION m<=n*n
//....
while (m <= n * n)
{
int n = 0;
scanf("%d", &n);
int arr[19][19] = { 0 };
int i = 0, j = 0;//控制数组下标的两个变量
int cow = n, col = n;//控制递增边界的两个变量
int sta1 = 0, sta2 = 0;//控制递减边界的两个变量
//具体思路是先右转,再下转,再左转,再上转,
//每一次转弯的标志是碰到边界
//右转
while (CONDITION && j < col)
{
arr[i][j] = m;
j++;
m++;
}
//下转
while (CONDITION && i < cow)
{
arr[i][j] = m;
i++;
m++;
}
//左转
while (CONDITION && j >= sta1)
{
arr[i][j] = m;
j--;
m++;
}
//上转
while (CONDITION && i > sta2)
{
arr[i][j] = m;
i--;
m++;
}
}
这里要注意一些细节:
-
在每次接触到边界后,控制数组下标的i或者j会有出界的现象,因为我们是递增/递减完后再去判断while的条件的。 例如:第一次向右时,j会一直自增到4(但是有效部分是0~3)即结束时i=0,j=4,为了不越界,所以每次转完都要对相应的出界元素进行操作。这里对j进行减减。
-
不仅是出界元素的问题,当我们决定从向右转而向下时,右和下的重叠元素究竟算是谁的呢?这里我们算作是上一个操作的元素。所以在对于转动操作完成时,也要对下标元素i / j进行移动。 例如:第一次右转时i会保持不变且一直为0,即第一次右转结束是i=0,j=4,但为了得到第一个向下的元素,即i=1,j=3,所以这里我们对i进行加加,以此类推解决每次递进。
-
最后我们不难看出,一次循环中右转、下转、左转的边界元素都不会变化,但是上转时,上边界发生了变化,所以这里注意:
while (CONDITION && i > sta2)
上边界不能取等号
修改了这些问题后:我们来看看最终的代码:
#define CONDITION m<=n*n
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int arr[19][19] = { 0 };
int m = 1;//控制自增的变量
int cow = n, col = n;//控制递增边界的两个变量
int sta1 = 0, sta2 = 0;//控制递减边界的两个变量
int i = 0, j = 0;//控制数组下标的两个变量
while (m <= n * n)
{
//具体思路是先右动,再下动,再左动,再上动,每一次转弯的标志是碰到边界
//右动
while (CONDITION && j < col)
{
arr[i][j] = m;
j++;
m++;
}
j--;//判断多了一次,越界了
i++;//位置重复了,坐标要往接下来的趋势变化
//下动
while (CONDITION && i < cow)
{
arr[i][j] = m;
i++;
m++;
}
i--;//判断多了一次,越界了
j--;//位置重复了,坐标要往接下来的趋势变化
col--; //右动和下动边界要变了
cow--;
//左动
while (CONDITION && j >= sta1)
{
arr[i][j] = m;
j--;
m++;
}
j++;//判断多了一次,越界了
i--;//位置重复了,坐标要往接下来的趋势变化
//上动
while (CONDITION && i > sta2)
{
arr[i][j] = m;
i--;
m++;
}
i++;//判断多了一次,越界了
j++;//位置重复了,坐标要往接下来的趋势变化
sta1++;//左动和上动的边界要变
sta2++;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
printf("%-1d ", arr[i][j]);
printf("\n");
}
return 0;
}
下面是我的输出结果:
n=3
n=5
n=9