问题描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵:
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.
由于是以外圈到内圈的顺序依次打印,所以我们可以把矩阵想象成若干个圈,这样就能用一个循环来打印矩阵了,每次打印矩阵中的一个圈。
分析循环结束的条件:
假设这个矩阵的行数是rows,列数是columns,打印第一圈的左上角的坐标(0,0),第二圈的坐标是(1,1),以此类推,可以发现,左上角的坐标中行和列的值总是相同的,于是可以在矩阵中选取左上角为(start,start)的一圈作为我们分析的目标。
对于5✖5的矩阵来说,最后一圈只有一个数字,对应的坐标为2✖2,可以发现5>2✖2 。对于一个6✖6的矩阵来说,最后一圈有4个数字,其左上角的左边仍然为(2,2)。我们发现6>2✖2依然成立。于是可以得出,让循环继续的条件是:columns>startX ✖ 2且rows>startY ✖ 2 。
接下来分析如何打印一圈的功能:
第一步,从左到右打印一行;
第二步,从上到下打印一列;
第三步,从右到左打印一行;
第四部,从下到上打印一列。
每一步我们根据起始坐标用一个循环就能打印出一行或者一列了。
但是,
最后一圈可能只有一行、一列,甚只有一个数字,因此打印这样的圈就不用四步了。
我们需要仔细判断打印的前提条件。
第一步总是需要的,因为打印一圈至少有一步。如果只有一行,那就不用第二步了。也就是第二步需要的前提条件是终止行号大于起始行号。第三步打印的前提条件是圈内至少有两行两列,也就是说,除了要求终止行号大于起始行号,还要求终止列号大于起始列号。第四步,前提条件是至少有三行两列,因此要求终止行号比起始行号至少大2,同时终止列号大于起始列号。
如果思考时难以理解,可以通过画几幅图来帮助理解,这样往往能够快速的打开思路。
以下为该问题的参考代码:
using System;
using System.Collections.Generic;
namespace 顺时针打印矩阵
{
class Program
{
static void Main(string[] args)
{
//Test1:二维数组有多行多列
Console.WriteLine("Test1:");
int[][] matrix = new int[5][];
matrix[0] = new int[] { 1, 2, 3, 4, 5 };
matrix[1] = new int[] { 6, 7, 8, 9, 10 };
matrix[2] = new int[] { 11, 12, 13, 14, 15 };
matrix[3] = new int[] { 16, 17, 18, 19, 20 };
matrix[4] = new int[] { 21, 22, 23, 24, 25 };
List<int> list = new List<int>();
list = PrintMatrix(matrix);
PrintList(list);
//Test2:二维数组就一列
Console.WriteLine("\nTest2:");
int[][] matrix1 = new int[5][];
matrix1[0] = new int[] { 1 };
matrix1[1] = new int[] { 2 };
matrix1[2] = new int[] { 3 };
matrix1[3] = new int[] { 4 };
matrix1[4] = new int[] { 5 };
List<int> list1 = new List<int>();
list1 = PrintMatrix(matrix1);
PrintList(list1);
//Test3:二维数组为空
Console.WriteLine("\nTest3:");
int[][] matrix2 = null;
List<int> list2 = new List<int>();
list2 = PrintMatrix(matrix2);
PrintList(list2);
}
public static List<int> PrintMatrix(int[][] matrix)
{
//如果传入的数组为空,返回空
if (matrix == null)
return null;
//如果传入的数组不为空,说明有行值,计算出行值
int columns = matrix.Length;
//如果行值大于1,则继续
if (columns <= 0)
return null;
//如果行值大于1,说明有不止一行,判断列值是否大于1,大于则继续
int rows = matrix[0].Length;
if (rows <= 0)
return null;
List<int> list = new List<int>();
int start = 0;
//判断是否已经遍历完最后一圈
while (columns > start * 2 && rows > start * 2)
{
//把每圈数字依次添加到List中
list.AddRange(PrintMatrixInCircle(matrix, columns, rows, start));
//当遍历完当前一圈,让起点的坐标更进一层
start++;
}
return list;
}
/// <summary>
/// 遍历一圈的值
/// </summary>
/// <param name="matrix">矩阵</param>
/// <param name="columns">矩阵的行</param>
/// <param name="rows">矩阵的列</param>
/// <param name="start">圈的起始位置</param>
/// <returns>一圈所有值的集合</returns>
private static List<int> PrintMatrixInCircle(int[][] matrix, int columns, int rows, int start)
{
int endX = rows - 1 - start;
int endY = columns - 1 - start;
List<int> list = new List<int>();
//从左往右打印一行
for (int i = start; i <= endX; i++)
{
list.Add(matrix[start][i]);
}
//从上往下打印一列
if (start < endY)
for (int i = start + 1; i <= endY; i++)
list.Add(matrix[i][endX]);
//从右往左打印一行
if (start < endX && start < endY)
for (int i = endX - 1; i >= start; i--)
list.Add(matrix[endY][i]);
//从下往上打印一列
if (start < endX && start < endY - 1)
for (int i = endY - 1; i >= start + 1; i--)
list.Add(matrix[i][start]);
return list;
}
/// <summary>
/// 打印集合list中的所有元素
/// </summary>
/// <param name="list">集合</param>
private static void PrintList(List<int> list)
{
if(list==null)
{
Console.WriteLine("null");
return;
}
foreach(int item in list)
{
Console.Write(item + "\t");
}
}
}
}