C++中rotate函数怎么旋转容器元素_C++标准库区间操作方法【函数】

2次阅读

std::rotate执行循环左移,参数为rotate(first, middle, last),将[first, middle)移到[middle, last)之后;对vector/deque用三步翻转o(n),list可能指针调整更高效,forward_list不支持。

C++中rotate函数怎么旋转容器元素_C++标准库区间操作方法【函数】

rotate 函数到底在转什么位置

std::rotate 不是按角度或方向旋转,而是把一个区间「循环左移」:以某个中间点为界,把前半段搬到后半段后面。比如 rotate(v.begin(), v.begin() + 2, v.end()) 表示“以第 2 个元素为 pivot,把 [begin, begin+2) 搬到 [begin+2, end) 后面”。结果等价于先取走前两元素,再追加到末尾。

关键要记住三个迭代器参数顺序:rotate(first, middle, last),其中 [first, middle) 是被挪走的前段,[middle, last) 是后段,最终变成 [middle, last) + [first, middle)

vector 和 list 上调用 rotate 的性能差异

std::rotate 对随机访问容器(如 std::vectorstd::deque)通常用三步翻转法(reverse 三次),时间复杂度 O(n),空间 O(1);对双向链表 std::list标准库可能直接调整指针,同样 O(n) 时间但常数更小;而对单向链表(如 std::forward_list),rotate 无法高效实现,c++17 起已明确不支持——调用会编译失败。

  • vector 时放心调用,无额外分配
  • list 时注意:虽然接口存在,但某些老编译器(如 GCC 4.8)可能退化成拷贝,建议实测 size() 大时的耗时
  • 别对 forward_listrotate,编译报错信息通常是 no matching function for call to 'rotate'

常见误用:middle 越界或迭代器失效

最常踩的坑是传错 middle —— 它必须落在 [first, last] 范围内(允许等于 last,此时等效于没动)。例如:

立即学习C++免费学习笔记(深入)”;

vector<int> v = {1,2,3,4,5}; rotate(v.begin(), v.begin() + 10, v.end()); // UB!middle 超出 end

另一个陷阱是,在 rotate 过程中修改容器大小(如 push_back)会导致所有迭代器失效,而 rotate 的三个参数都是迭代器,一旦失效,行为未定义。

  • 调用前用 assert(middle >= first && middle 防御性检查(调试模式下)
  • 避免在 rotate 前后紧邻地调用 eraseinsert,尤其当用的是同一容器的迭代器时
  • 如果 middle 来自 find 等算法结果,务必检查是否等于 last(即未找到),否则解引用会崩溃

替代方案:什么时候不该用 rotate

如果只是想把最后一个元素移到开头,或者把第一个移到末尾,用 rotate 是杀鸡用牛刀。更清晰的做法是:

  • 末尾→开头:v.insert(v.begin(), v.back()); v.pop_back();
  • 开头→末尾:v.push_back(v.front()); v.erase(v.begin());

这些操作语义直白,且对小容器(如 size rotate 内部至少涉及 2n 次赋值(三步翻转),在 tiny range 下反而有额外开销。只有当你需要任意切分点的循环移位,且容器较大时,rotate 的 O(n) 原地优势才真正体现出来。

真正容易被忽略的是:rotate 不改变容器 size,也不做任何类型转换或构造,它只重排已有对象的内存位置——所以如果元素类型有非平凡移动构造,性能取决于该类型的移动效率,而非 rotate 本身。

text=ZqhQzanResources