趣味编程-螺旋打印
描述
给定一个自然数n,打印1-n之间所有的数,要求:按螺旋形状顺时针打印。以前看到过这道题,说的是从外向内螺旋打印,而前几天又看到一个变种,由内向外打印。比之前的稍微难一点,趁周末闲着没事,总结一下。先上两幅图,大家看一下效果。
由外向内打印
由内向外打印
这两种输出方法,其实大同小异,道理都差不多,会了一种,则另一种不难,先看从外向内打印的
分析
最简单且直观的方法就是k * k的二维数组存储数字,先将数字按照要求填入数组,然后输出整个数组即可
分配数组
对于n个数而言,令k = Ceil(sqrt(n)), 则分配k*k的二维数组即可。比如n = 5时,分配3*3的数组即可。
如何填数
起始点
以左上角为起始点
方向
用一个整数flag来标识方向
flag = 1 - 向右
flag = 2 - 向下
flag = 3 - 向左
flag = 4 - 向上
边界判断
当到达边界的时候应该变换方向,即向右转,如何判断边界?我的方法是,将所有数组元素初始化为-1,则有如下两种情况
1.下标超出二维数组边界,则需转向(注意,转向之前下标需要退回一格)
2.下标未越界,但下一个位置的值不是-1,那么说明它被填充过,也需转向。
填充
重复以下过程直到所有数据填充完毕。
1. 从左至右填充数组,如遇右边界或者下一位置已经被填充过,则改变方向,转入步骤2
2. 从上至下填充数组,如遇下边界或者下一位置已经被填充过,则改变方向,转入步骤3
3. 从右至左填充数组,如遇左边界或者下一位置已经被填充过,则改变方向,转入步骤4
4. 从下至上填充数组,如遇上边界或者下一位置已经被填充过,则改变方向,转入步骤1
整个填充过程如下图
代码
有了以上思路,则写代码不是难事
由内向外填充
如果上面的搞懂了,则这个也就不难了,不过有一些细节上的东西还需修改一下
起始位置
由于是从内向外填充,所以起始位置不再是(0, 0),需要重新计算,而且还与二维数组的阶数k的奇偶性相关
1 当k为奇数时,起始位置为(k / 2, k / 2),如下:
k = 3,起始位置为(1, 1)
7 8 9
6 1 2
5 4 3
2 当k为偶数时,起始位置为(k / 2 - 1, k / 2 - 1),如下:
k = 4,起始位置为(1, 1)
7 8 9 10
6 1 2 11
5 4 3 12
16 15 14 13
边界判断
与从外向内填充不同的是,边界判断中不会再出现下标越界的情况,只需判断当前位置是否填充过即可
方向转换
从内向外填充时,能转向时优先转向,不能转向时才继续向前填充,而从外向内填充则恰恰相反,无法继续向前填充时才转向。