螺旋矩阵的定义与问题

螺旋矩阵是指一个n×n的二维数组,其中的元素按照从左到右、从上到下、从右到左、从下到上的螺旋顺序依次填充,3×3的螺旋矩阵为:
1 2 3
8 9 4
7 6 5
其核心问题在于如何按照螺旋顺序填充数字,或按螺旋顺序遍历已有矩阵,本文将重点讲解如何用Java生成一个n×n的螺旋矩阵,并分析其中的关键逻辑与边界处理。
算法思路:分层遍历法
生成螺旋矩阵的核心思路是“分层遍历”,将矩阵视为由外向内嵌套的多个层,每层是一个“空心正方形”,按照“上→右→下→左”的顺序遍历并填充数字,具体步骤如下:
- 初始化矩阵:创建一个n×n的二维数组,初始值可设为0或任意占位符,用于后续填充。
- 确定层数:对于n×n矩阵,共有
(n + 1) / 2层(例如n=3时为2层,n=4时为2层)。 - 分层填充:对于每一层,确定其边界(起始行、起始列、结束行、结束列),按顺序遍历四个边:
- 上边:从左到右遍历,填充起始行的列区间
[startCol, endCol]; - 右边:从上到下遍历,填充结束列的行区间
[startRow + 1, endRow]; - 下边:从右到左遍历,填充结束行的列区间
[endCol - 1, startCol](需确保当前层不止一行); - 左边:从下到上遍历,填充起始列的行区间
[endRow - 1, startRow + 1](需确保当前层不止一列)。
- 上边:从左到右遍历,填充起始行的列区间
- 更新边界:每层填充完成后,起始行、起始列加1,结束行、结束列减1,进入下一层遍历。
Java代码实现与关键步骤解析
以下是生成n×n螺旋矩阵的完整Java代码,包含详细注释:
public class SpiralMatrixGenerator {
public static int[][] generateSpiralMatrix(int n) {
// 初始化n×n矩阵,初始值为0
int[][] matrix = new int[n][n];
int currentNum = 1; // 当前要填充的数字
int startRow = 0, startCol = 0; // 当前层的起始行、列
int endRow = n - 1, endCol = n - 1; // 当前层的结束行、列
while (startRow <= endRow && startCol <= endCol) {
// 1. 填充上边:从左到右
for (int col = startCol; col <= endCol; col++) {
matrix[startRow][col] = currentNum++;
}
startRow++; // 起始行下移,进入下一层
// 2. 填充右边:从上到下
for (int row = startRow; row <= endRow; row++) {
matrix[row][endCol] = currentNum++;
}
endCol--; // 结束列左移,进入下一层
// 3. 填充下边:从右到左(需确保当前层不止一行)
if (startRow <= endRow) {
for (int col = endCol; col >= startCol; col--) {
matrix[endRow][col] = currentNum++;
}
endRow--; // 结束行上移,进入下一层
}
// 4. 填充左边:从下到上(需确保当前层不止一列)
if (startCol <= endCol) {
for (int row = endRow; row >= startRow; row--) {
matrix[row][startCol] = currentNum++;
}
startCol++; // 起始列右移,进入下一层
}
}
return matrix;
}
// 打印矩阵的方法(辅助测试)
public static void printMatrix(int[][] matrix) {
for (int[] row : matrix) {
for (int num : row) {
System.out.printf("%3d", num);
}
System.out.println();
}
}
public static void main(String[] args) {
int n = 4;
int[][] spiralMatrix = generateSpiralMatrix(n);
printMatrix(spiralMatrix);
}
}
关键步骤解析:
- 边界控制:通过
startRow、startCol、endRow、endCol动态调整每层的遍历范围,确保不会重复填充或越界。 - 方向切换:每完成一个方向的遍历,更新对应边界(如上边遍历后
startRow++),并切换到下一个方向。 - 终止条件:当
startRow > endRow或startCol > endCol时,说明所有层已遍历完成,循环终止。
边界条件与特殊情况处理
在实现螺旋矩阵时,需特别注意以下边界情况:

-
n=0或n=1:
- n=0时,应返回空矩阵或抛出异常(根据需求);
- n=1时,矩阵直接为
[[1]],无需复杂遍历。
代码中while循环的条件startRow <= endRow && startCol <= endCol已自然处理n=1的情况。
-
非方阵(m×n):
若需生成m×n的螺旋矩阵(如3×4),只需调整层数为Math.min(m, n) / 2,并在遍历时判断行数和列数是否足够,填充右边时需判断startRow <= endRow,填充下边时需判断startCol <= endCol(避免单行或单列时重复遍历)。 -
数字填充连续性:
通过currentNum变量确保数字从1开始连续填充,每填充一个数字自增1,避免遗漏或重复。
空间优化与性能分析
- 时间复杂度:O(n²),因为矩阵中每个元素仅被访问和填充一次。
- 空间复杂度:O(n²),用于存储生成的矩阵,若仅需遍历螺旋顺序而不存储结果(如打印),可优化至O(1)额外空间(但需提前给定矩阵)。
对于生成螺旋矩阵的场景,空间复杂度无法进一步优化,因为结果本身就是n×n的二维数组。
小编总结与扩展方向
本文通过“分层遍历法”实现了Java螺旋矩阵的生成,核心在于动态调整边界和按序切换遍历方向,关键点包括:

- 明确每层的四个边界,避免越界和重复填充;
- 处理单行或单列的特殊情况,防止方向遍历时逻辑错误;
- 通过边界更新和循环终止条件确保遍历完整性。
扩展方向包括:
- 螺旋矩阵遍历:给定一个已填充的矩阵,按螺旋顺序输出元素(类似LeetCode“螺旋矩阵”问题);
- 逆螺旋矩阵:按照从外到内逆螺旋顺序填充(如“下→左→上→右”);
- 动态螺旋矩阵:根据输入的行数和列数生成非方阵螺旋矩阵。
掌握螺旋矩阵的实现逻辑,有助于深化对二维数组遍历和边界控制的理解,为后续复杂算法设计奠定基础。
















