趣味编程-螺旋打印

描述

给定一个自然数n,打印1-n之间所有的数,要求:按螺旋形状顺时针打印。以前看到过这道题,说的是从外向内螺旋打印,而前几天又看到一个变种,由内向外打印。比之前的稍微难一点,趁周末闲着没事,总结一下。先上两幅图,大家看一下效果。

由外向内打印

2010060520131173.jpg

由内向外打印

2010060520132741.jpg

这两种输出方法,其实大同小异,道理都差不多,会了一种,则另一种不难,先看从外向内打印的

分析

最简单且直观的方法就是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

整个填充过程如下图

 2010060520242933.jpg

代码

有了以上思路,则写代码不是难事

ContractedBlock.gif 代码

由内向外填充

如果上面的搞懂了,则这个也就不难了,不过有一些细节上的东西还需修改一下

起始位置

由于是从内向外填充,所以起始位置不再是(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

边界判断

与从外向内填充不同的是,边界判断中不会再出现下标越界的情况,只需判断当前位置是否填充过即可

方向转换

从内向外填充时,能转向时优先转向,不能转向时才继续向前填充,而从外向内填充则恰恰相反,无法继续向前填充时才转向。

代码

ContractedBlock.gif 代码

本文转自zdd博客园博客,原文链接: http://www.cnblogs.com/graphics/archive/2010/06/05/1739658.html ,如需转载请自行联系原作者