关于回旋矩阵的几点思考
(数组-不使用数组)
某日,友人出题,要求 N*N的回旋矩阵的输出。
回旋矩阵,顾名思义,就是从外圈数字由大到小旋转到内圈的N阶矩阵
例如 :
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
便是一个5*5的回旋矩阵。
对于这类问题,首先想到的是通过数组进行输出,现在数组中对各个位置的数进行排列,再由for循环对数组进行输出操作。如此思路清晰,代码明了,也不易出错。
#include <stdio.h>
#define N 16 //在此定义 矩阵的大小
int main(int argc, const char * argv[])
{
int a[N][N] = {0};
int i ,j ,x ,y ,m = 0; //左x 右y
//计算部分
for ( x = 0 ; x < N / 2 ; x++) { //x是下限
y = N - x - 1; // y是上限
if ( m == N * N) {
break;
}
for ( i = x ; i < y ; i++) {
m++;
a[i][x] = m;
}
if ( m == N * N) {
break;
}
for ( i = x ; i < y ; i++ ) {
m++;
a[y][i] = m;
}
if ( m == N * N) {
break;
}
for ( j = y ; j > x ; j-- ){
m++;
a[j][y] = m;
}
if ( m == N * N) {
break;
}
for ( j = y ; j > x ; j-- ){
m++;
a[x][j] = m;
}
}
if ( N % 2 != 0) {
int r = N / 2 ;
a[r][r] = N * N; //判读是否奇数 消除以上打表方法的小BUG
}
//打印部分
for (i = 0 ; i < N ; i++) {
for ( j = 0 ; j < N ; j++) {
printf("%4d ", a[j][i]);
}
printf("\n\n");
}
return 0;
}
此处使用宏定义定义阶层N的值,算是偷了一点懒,若需手动录入N的大小,可以先建一个100*100的二位数组(10*10)也可,再将读入的数的值赋值给N,代码几乎相同,此处不再赘述。
此处思路是大环套小环的“嵌套”思路,即由外圈向内,逐圈进行计算,得益于数组可以先计算再输出的所谓优点,可以先计算出每一圈各个位置的每个数之后,再进行整体的输出。这里的方法更将每一环切分为4小段,再对每一段上的每一个数进行填充。其中N为奇数时因为for循环判断的机制,所以出现了一个Bug,导致最中心的数无法进行填充,最后通过特殊法对N进行判断,填充了中心的缺口。最后以二重for循环对二维数组进行打印输出。
这里的方法并不是非常的好,大家肯定有更好的办法。那么能不能不用数组呢?办法是有的。
#include <iostream>
#include <iomanip>
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
using namespace std;
int matrix(int i, int j, int n);
int main(int argc, const char * argv[])
{
int n, i, j;
cout << "Please input n:";
cin >> n;
for (j = 0; j < n; j++) {
for (i = 0; i < n; i++) {
cout << setw(4) <<matrix(j, i, n);
}
cout << endl <<endl;
}
return 0;
}
int matrix(int i, int j, int n)
{
int m, a, l;
m = min( min( i, n-1-i ), min( j, n-1-j ) ); //计算在第几环
i -= m;
j -= m;
a = 1 + 4*m*(n-m); //首元素
l = n - 2*m; // 环边长
if (i == 0)
return a+j;
else if (j == 0)
return a + 4*(l-1) - i;
else if (i == l-1)
return a + 4*l - 3 - l - j;
return a + l-1 + i;
}