C版——打印螺旋矩阵

1.递归解法

递归解法如下:

+--------------------------> X 轴

| 1   2   3   4

|  12 13 14 5

|  11 16 15 6

|  10 9   8   7

|

Y轴

设元素1的坐标为(0,0),元素13的坐标为(1,1),……,任一元素的坐标为(x,y)

 1 #include <stdio.h>
 2
 3 void SetMatrix(int **matrix, int x, int y, int start, int n) {
 4     int i, j;
 5     if (n <= 0)
 6         return;
 7     if (n == 1) {
 8         matrix[x][y] = start;
 9         return;
10     }
11     for (i = x; i < x + n-1; i++)          /* 上部 */
12         matrix[y][i] = start++;
13     for (j = y; j < y + n-1; j++)          /* 右边 */
14         matrix[j][x+n-1] = start++;
15     for (i = x+n-1; i > x; i--)              /* 底部 */
16         matrix[y+n-1][i] = start++;
17     for (j = y+n-1; j > y; j--)              /* 左边 */
18         matrix[j][x] = start++;
19     SetMatrix(matrix, x+1, y+1, start, n-2);     /* 递归 */
20 }
21
22 void main() {
23     int i, j;
24     int n;
25     int **matrix; //螺旋矩阵(二维数组)
26     printf("请输入方阵的大小");
27     scanf("%d", &n);
28     matrix = (int **)malloc(n * sizeof(int *)); //为矩阵分配空间
29     for (i = 0; i<n; i++)
30         matrix[i] = (int *)malloc(n * sizeof(int));
31
32     SetMatrix(matrix, 0, 0, 1, n);
33
34     //打印螺旋矩阵
35     for(i = 0; i < n; i++) {
36         for (j = 0; j < n; j++)
37             printf("%4d", matrix[i][j]);
38         printf("\n");
39     }
40 }

但该方法只可以解决方阵问题。

*摘自http://blog.csdn.net/blackeagle_/article/details/606341

2.非递归解法

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

例如:如果输入如下矩阵:

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

则依次打印出数字1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10。

分析:第一次看到这个题目的时候,觉得这个题目很简单,完全不需要用到数据结构或者算法的知识,因此没有兴趣做这道题。后来听到包括Autodesk、EMC在内的多家公司在面试或者笔试里采用过这道题,于是想这么多家公司用它来检验一个程序员的编程功底总是有原因的,于是决定自己写一遍试一下。真正写一遍才发现,要完整写出这道题的代码,还真不是件容易的事情。

解决这道题的难度在于代码中会包含很多个循环,而且还有多个边界条件需要判断。如果在把问题考虑得很清楚之前就开始写代码,不可避免地会越写越混乱。因此解决这个问题的关键,在于先要形成清晰的思路,并把复杂的问题分解成若干个简单的问题。下面分享我分析这个问题的过程。

通常当我们遇到一个复杂的问题的时候,我们可以用图形帮助我们思考。由于我们是以从外圈到内圈的顺序依次打印,我们在矩阵中标注一圈作为我们分析的目标。在下图中,我们设矩阵的宽度为columns,而其高度为rows。我们我们选取左上角坐标为(startX, startY),右下角坐标为(endX, endY)的一个圈来分析。

由于endX和endY可以根据startX、startY以及columns、rows来求得,因此此时我们只需要引入startX和startY两个变量。我们可以想象有一个循环,在每一次循环里我们从(startX, startY)出发按照顺时针打印数字。

接着我们分析这个循环结束的条件。对一个5×5的矩阵而言,最后一圈只有一个数字,对应的坐标为(2, 2)。我们发现5 > 2 * 2。对一个6×6的矩阵而言,最后一圈有四个数字,对应的坐标仍然为(2, 2)。我们发现6 > 2 * 2依然成立。于是我们可以得出,让循环继续的条件是columns > startX * 2 && rows > startY * 2。有了这些分析,我们就可以写出如下的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

void PrintMatrixClockwisely(int** numbers, int columns, int rows)

{

        if(numbers == NULL || columns <= 0 || rows <= 0)

                return;

 

        int startX = 0;

        int startY = 0;

 

        while(columns > startX * 2 && rows > startY * 2)

        {

                PrintMatrixInCircle(numbers, columns, rows, startX, startY);

 

                ++startX;

                ++startY;

        }

}

接下来我们分析如何在PrintMatrixInCircle中按照顺时针的顺序打印一圈的数字。如同在图中标注的那样,我们可以分四步来打印:第一步是从左到右打印一行(上图中黄色区域),第二步是从上到下打印一列(上图中绿色区域),第三步从右到左打印一行(上图中蓝色区域),最后一步是从下到上打印一列(上图中紫色区域)。也就是我们把打印一圈数字这个问题,分解成四个子问题。我们可以为每个子问题定义一个函数。四个步骤对应的函数名称我们分别定义为:PrintARowIncreasingly,PrintAColumnIncreasingly,PrintARowDecreasingly和PrintAColumnDecreasingly。

现在我们暂时不考虑如何去实现这四个函数,而是先考虑我们需要分别给这些函数传入哪些参数。第一步打印一行时,所有的数字的行号是固定的(startY),不同数字的列号不同。我们需要传入一个起始列号(startX)和终止列号(endX)。第二步打印一列时,所有的数字的列号是固定的,不同的数字的行号不同。我们需要传入一个起始行号(startY + 1)和一个终止行号(endY)。第三步和第四步和前面两步类似,读者可以自己分析。

接下来我们需要考虑特殊情况。并不是所有数字圈都需要四步来打印。比如当一圈退化成一行的时候,也就是startY等于endY的时候,我们只需要第一步就把所有的数字都打印完了,其余的步骤都是多余的。因此我们需要考虑第二、三、四步打印的条件。根据前面我们分析,不难发现打印第二步的条件是startY < endY。对于第三步而言,如果startX等于endX,也就是这一圈中只有一列数字,那么所有的数字都在第二步打印完了;如果startY等于endY,也就是这一圈中只有一行数字,那么所有的数字都在第一步打印完了。因此需要打印第三步的条件是startX < endX && startX < endY。第四步最复杂,首先startX要小于endX,不然所有的数字都在一列,在第二步中就都打印完了。另外,这个圈中至少要有三行数字。如果只有一行数字,所有数字在第一步中打印完了;如果只有两行数字,所有数字在第一步和第三步也都打印完了。因此打印第四步需要的条件是startY < endY – 1。

有了前面的分析,我们就能写出PrintMatrixInCircle的完整代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

void PrintMatrixInCircle(int** numbers, int columns, int rows,

                                  int startX, int startY)

{

        int endX = columns - 1 - startX;

        int endY = rows - 1 - startY;

 

        PrintARowIncreasingly(numbers, columns, rows, startY, startX, endX);

 

        if(startY < endY)

                PrintAColumnIncreasingly(numbers, columns, rows, endX, startY + 1, endY);

 

        if(startX < endX && startY < endY)

                PrintARowDecreasingly(numbers, columns, rows, endY, endX - 1, startX);

 

        if(startX < endX && startY < endY - 1)

                PrintAColumnDecreasingly(numbers, columns, rows, startX, endY - 1, startY + 1);

}

接下来我们考虑如何打印一行或者一列。这对我们来说不是一件很难的事情。以函数PrintARowIncreasingly为例,我们只需要一个循环,把行号为startY,列号从startX到endX的所有数字依次从数组中取出来并逐个打印就行了,对应的代码是:

1

2

3

4

5

6

7

8

void PrintARowIncreasingly(int** numbers, int columns, int rows,

                                int y, int firstX, int lastX)

{

        for(int i = firstX; i <= lastX; ++i)

        {

                int number = *(*(numbers + y) + i);

        printf("%d\t", number);

        }

}

剩下的三个函数与此类似,代码依次如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

void PrintAColumnIncreasingly(int** numbers, int columns, int rows,

                                  int x, int firstY, int lastY)

{

        for(int i = firstY; i <= lastY; ++i)

        {

                int number = *(*(numbers + i) + x);

        printf("%d\t", number);

        }

}

void PrintARowDecreasingly(int** numbers, int columns, int rows,

                                int y, int firstX, int lastX)

{

        for(int i = firstX; i >= lastX; --i)

        {

                int number = *(*(numbers + y) + i);

        printf("%d\t", number);

        }

}

void PrintAColumnDecreasingly(int** numbers, int columns, int rows,

                                  int x, int firstY, int lastY)

{

        for(int i = firstY; i >= lastY; --i)

        {

                int number = *(*(numbers + i) + x);

        printf("%d\t", number);

        }

}

*摘自http://www.cnblogs.com/dartagnan/archive/2011/10/08/2201682.html

其中,评论第一条令我感觉眼前一亮

「看了题目,第一的反应把矩阵放到二维数组里,依次往右,往下,往左,往上循环打印」

时间: 2024-08-03 21:50:23

C版——打印螺旋矩阵的相关文章

剑指offer (20) 打印螺旋矩阵

题目描述: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字 class Solution { public: vector<int> spiralOrder(vector<vector<int> > &matrix) { vector<int> result; int nRows = matrix.size(); if (nRows == 0) return result; int nCols = matrix.at(0).size()

打印螺旋矩阵数字

明确了方阵数字是螺旋递增以后,发现每一个"口"字型的一圈数字正好闭合且连续递增.所以解题思路是由"口"字型的 递增依次向内嵌套.先填充最外层"口"字型的一圈数字,接着填充次外层--最后填充最内层的四个数.由一些较简单的画图可以 看出,层数的奇偶会影响到最内层的填充.当为奇数时,最内层只剩一个数字需要填充.所以奇数层需要单独考虑. 先是填充顶部的(n-1)个数字,接着由顶部的最后一个数字开始向下,填充右部的(n-1)个数字,接着是底部的(n-1)个

打印螺旋矩阵

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<math.h> 4 5 #define MAX 64 6 7 void initArray(int array[][MAX], int n); 8 void printArray(int array[][MAX], int n); 9 10 int main() 11 { 12 int n; 13 int array[MAX][MAX]; 14 printf(&quo

编程题之打印二维螺旋矩阵

当size=4时, 二维螺旋矩阵如下图所示: 规律总结 可以把这个二维矩阵看成一层套一层,如上图所示,1->4->7->10->12为第零层, 13->14->15->16为第一层,所以当size=4时,总共有两层.规律如下: 可分层数为:若size为偶数,层数=size/2, 若为奇数,则层数=(size+1)/2; 第n层一个方向上的数字的数量为:size-2*n; 这是因为第零层的一个方向上数字的数量就是size, 而第一层是size-2,...第n层就是s

Java-基础编程(螺旋矩阵&amp;乘法表)

package cn.rick.study; import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.Scanner; /** * * @author Rick-bao date 2014-8-29 * */public class SomeBasicCode { public static void main(String[] args) { MultiplicationTable();//

HLG 1564 螺旋矩阵 (趣味C语言)

链接: http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1564 Description 对于给定的一个数n,要你打印n*n的螺旋矩阵. 比如n=3时,输出: 1 2 3 8 9 4 7 6 5 Input 多组测试数据,每个测试数据包含一个整数n(1<=n<=32) Output 对于每组测试数据,输出一个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 如果我们需要打印这样从外部向内扩展的n * n矩阵. 分析: 可以把矩阵分为n/2个圈, (上面的例子分了两个圈,最外面的圈就是12345~16,另外一个圈就是17~24) 我们只需要以圈为单位,给二维数组中的每个数赋值.赋值的顺序也是按照数字的递增顺序(顺时针) Java代码如下: public class SpiralMatrix

PHP实现螺旋矩阵(螺旋数组)

今天碰到一个比较有意思的问题, 就是把A到Y这25个字母以下面的形式输出出来 A B C D E P Q R S F O X Y T G N W V U H M L K J I 问题很有意思,就是转圈圈把字母填到表格中,要输出这样的格式,其实就需要构造一个下面这样的表格 1 2 3 4 5 16 17 18 18 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9 这其实是一个螺旋矩阵的问题, 这跟下面这个问题本质是一样的: 给定一个行数row和列数cols,

代码题(37)— 螺旋矩阵

1.54. 螺旋矩阵 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素. 示例 1: 输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 输出: [1,2,3,6,9,8,7,4,5] 示例 2: 输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出: [1,2,3,4,8,12,11,10,9,5,6,7]    思想:用左上和右下的坐标定位出一次要旋