数组左右旋转的实质是逻辑重排而非逐个移动:左旋k位即前k个元素移至末尾,右旋k位即后k个元素移至开头;k需先对长度取模,再用std::rotate或三步翻转实现。

什么是数组左右旋转的实质操作
数组旋转不是逐个移动元素,而是对内存中连续段落做逻辑重排。左旋 k 位,等价于把前 k 个元素移到末尾;右旋 k 位,则是把后 k 个元素移到开头。关键点在于:旋转位数 k 要先对数组长度取模,否则越界或重复旋转——比如长度为 5 的数组右旋 7 位,实际只需右旋 7 % 5 = 2 位。
常见错误现象:k 直接用原值导致越界访问、下标计算错乱;未处理 k == 0 或空数组导致未定义行为。
- 使用场景:环形缓冲区模拟、密码学位移、LeetCode 第 189 题
- 性能影响:O(1) 空间 + O(n) 时间的三步翻转法比额外开数组更优
- 兼容性注意:C++11 起
std::rotate已支持双向迭代器,但底层仍是三步翻转
用 std::rotate 快速实现(推荐日常使用)
C++ 标准库提供了现成且安全的方案:std::rotate 在 <algorithm> 中,接受三个迭代器:[first, middle, last),将 [first, middle) 搬到 [middle, last) 后面。左旋 k 就是把开头 k 个“搬走”,右旋则等价于左旋 n - k,或直接调换 middle 位置。
#include <algorithm>
#include <vector>
std::vector<int> arr = {1,2,3,4,5};
int k = 2;
k %= arr.size(); // 必须!
// 右旋 k 位 → 等价于左旋 (n-k) 位
std::rotate(arr.begin(), arr.begin() + arr.size() - k, arr.end());
// 此时 arr 变为 {4,5,1,2,3}
注意:std::rotate 对 std::array、原生数组指针也适用,但传入的迭代器必须合法——arr.begin() + offset 不能越界。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
手写三步翻转法(面试/理解原理必会)
不依赖 STL 时,靠三次 reverse 实现 O(1) 空间旋转:
① reverse 整个数组
② reverse 前 k 个
③ reverse 后 n−k 个
右旋 k 位就按这个顺序;左旋则把②③对调。
为什么这样可行?举例右旋 2 位:[1,2,3,4,5]
→ ① 全翻:[5,4,3,2,1]
→ ② 前 2 个翻:[4,5,3,2,1]
→ ③ 后 3 个翻:[4,5,1,2,3] ✅
- 容易踩的坑:reverse 区间是 [first, last),别写成
reverse(first, first+k)(漏掉第 k 个) - 参数差异:手写函数建议接收
vector<T>&或指针+长度,避免拷贝 - 边界条件:当
k == 0或arr.empty(),直接 return,别进 reverse
原生数组和 std::array 的适配要点
std::rotate 和手写翻转都支持原生数组,但需传指针而非数组名:std::rotate(a, a + k, a + n)。而 std::array 因为有 .data() 和 .size(),可无缝替代 vector 使用。
错误示范:int a[5] = {1,2,3,4,5}; std::rotate(a, a+2, a); —— 第三个参数写成 a 导致区间为空,结果未定义。
- 正确写法:
std::rotate(a, a + (n - k) % n, a + n)(右旋) - 编译期数组注意:若
k是非 constexpr,std::array仍可运行,但无法在 constexpr 上下文中用 - 性能提示:对小数组(≤ 16 元素),编译器可能把三步翻转完全内联,甚至优化成几个 mov 指令
实际写的时候,优先用 std::rotate;需要深挖机制或受限环境(如裸机、no-STL)时,三步翻转才是可靠底牌。旋转本身简单,但 k % n 这一步漏掉,后面全白忙。

















