顺时针旋转90°时,matrixi→new_matrixj(m为原行数);非方阵需先申请n×m维新矩阵;in-place旋转须分层处理环状置换。

旋转 90° 时,matrix[i][j] 应该落到哪里?
不是靠记忆公式,而是从坐标系出发:原矩阵第 i 行、第 j 列的元素,在顺时针旋转 90° 后,会出现在新矩阵的第 j 行、倒数第 i+1 列,即 new_matrix[j][n-1-i](假设原矩阵是 n×n)。逆时针则是 new_matrix[n-1-j][i]。
关键点在于——这个映射只对**方阵**直接成立;如果是 m×n 矩阵顺时针转 90°,结果是 n×m 矩阵,对应关系变为:matrix[i][j] → new_matrix[j][m-1-i](注意这里用的是原行数 m)。
- 别硬背
[j][n-i-1],先画个 3×3 小图,标出(0,0)、(0,1)、(2,0)转完去哪 - 如果原矩阵非方阵,
new_matrix的维度必须提前申请为n行m列(顺时针) - 用
vector<vector>></vector>时,别忘了resize(n, vector<int>(m))</int>再赋值,否则访问越界
就地旋转(in-place)为什么必须分层处理?
因为单个元素移动会“踩掉”还没处理的值。例如 (0,0) → (0,n-1) → (n-1,n-1) → (n-1,0) → (0,0),这四个位置构成一个环。只有按“圈”(layer)逐层、逐环搬运,才能避免覆盖。
对于 n×n 矩阵,总共有 n/2 层(向下取整),每层处理上边一行(不含最右)、右边一列(不含最下)、下边一行(不含最左)、左边一列(不含最上)。
- 外层循环:for
(int layer = 0; layer - 内层索引范围:
first = layer,last = n - 1 - layer - 每次交换四元组:
(first,j)→(j,last)→(last,last-j+first)→(last-j+first,first)(注意中间两个下标要平移) - 一旦写错平移量,比如漏了
+first,就会把某行全刷成 0 或随机值
std::swap 在就地旋转中能简化逻辑,但要注意顺序
用四次 std::swap 替代手动暂存变量,代码更干净,但顺序不能错:必须沿旋转方向依次交换,否则会反转两次回到原位。
顺时针 90° 的安全顺序是:
std::swap(matrix[first][j], matrix[j][last]); std::swap(matrix[first][j], matrix[last][last-j+first]); std::swap(matrix[first][j], matrix[last-j+first][first]);
注意:四次 swap 中,第一个操作数始终是 matrix[first][j](即当前“起点”),这样能保证它最终走到正确位置;其余三个位置被轮换一次后也归位。
- 如果改成两两 swap(如先 swap 左上和右上),大概率会得到镜像或错位结果
- 使用
std::swap前确认元素类型支持(int、double没问题,自定义类需提供移动构造或拷贝赋值) - 在 C++11 及以后,
std::swap对vector是 O(1)(交换内部指针),但对二维vector的单行 swap 仍是 O(n),不影响整体复杂度
测试时最容易忽略的边界:0 行、1 行、奇数阶矩阵中心点
空矩阵(m==0 || n==0)或单行/单列矩阵旋转后只是转置+翻转,但代码若没判空,for 循环可能不执行或越界访问 matrix[0][0]。
奇数阶(如 5×5)时,最内层是单个元素(layer == 2 时 first == last),此时内层循环 for (int j = first; j 不会执行——这是对的,中心点不动。但如果循环条件写成 <code>j ,就会多跑一次,导致越界或错误覆盖。
- 所有循环起始/结束条件统一用
,不要混用 <code> - 测试用例至少覆盖:
0×0、1×5、4×3、5×5、3×1 - 打印输出时,用
printf("%3d ", matrix[i][j])对齐,比纯cout更容易看出错位
实际写的时候,先跑通一个固定尺寸(如 4×4)的手动推演,再泛化到变量尺寸;矩阵旋转看着简单,真正卡住人的永远是下标偏移那一两个 ±1。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!









