You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

每次push_back重分配时,std::vector::push_back的时间复杂度是常数还是线性?

强制每次push_back重分配时,std::vector::push_back的摊还复杂度分析

直接给结论:这种修改后的push_back摊还复杂度不再是O(1),而是O(n)。下面一步步解释为什么:

先搞懂摊还复杂度的本质

摊还复杂度看的不是单次操作的最坏情况,而是连续执行n次操作的总时间,再平均到每次的成本。原std::vector的O(1)摊还复杂度,核心是扩容策略带来的总时间可控。

原翻倍扩容的总时间计算

原实现里,std::vector每次扩容把容量翻一倍(比如从1到2,2到4,4到8...)。假设我们做n次push_back:

  • 第1次扩容:容量从0变1,不用拷贝元素,耗时O(1)
  • 第2次扩容:容量从1变2,拷贝1个元素,耗时O(1)
  • 第4次扩容:容量从2变4,拷贝2个元素,耗时O(2)
  • 第8次扩容:容量从4变8,拷贝4个元素,耗时O(4)
  • ...

所有扩容的拷贝总耗时是1+2+4+...+n/2,这个和小于2n,所以n次操作总耗时是O(n),平均下来每次就是O(1)的摊还复杂度。

每次都扩容的总时间计算

现在改成每次push_back都重分配(比如每次容量只加1),n次操作的总耗时就完全不一样了:

  • 第1次:分配容量1,无拷贝,O(1)
  • 第2次:分配容量2,拷贝1个元素,O(1)
  • 第3次:分配容量3,拷贝2个元素,O(2)
  • 第4次:分配容量4,拷贝3个元素,O(3)
  • ...
  • 第n次:分配容量n,拷贝n-1个元素,O(n-1)

把这些耗时加起来,总和是0+1+2+...+(n-1) = n(n-1)/2,这是**O(n²)**的总耗时。平均到每次操作,摊还复杂度就是O(n)——随着n增大,每次操作的平均耗时会线性增长,根本达不到O(1)。

关于“常数部分”的说明

你提到“每次push_back都需遍历向量中所有元素”,这里的遍历(拷贝)的常数开销其实不是重点。摊还复杂度关心的是时间随数据规模增长的量级,哪怕拷贝每个元素的速度再快,总耗时是平方级的,摊还后的平均耗时还是会跟着n变大而线性上升,不可能维持O(1)的水平。


内容的提问来源于stack exchange,提问作者dau_sama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:13:36