咨询大N下vector代码的内存分配操作时间复杂度分析是否正确
你的理解有点小偏差哦,咱们一步步拆解这段代码的内存分配开销,搞清楚正确的时间复杂度~
先明确vector的扩容机制
在GCC里,std::vector的扩容规则确实是每次把容量翻一倍。当push_back发现当前容量装不下新元素时,会做这几件事:
- 分配一块容量为原容量2倍的新内存;
- 把原内存里的所有元素拷贝到新内存;
- 释放原内存;
- 再把新元素加进去。
单次扩容的开销是O(当前容量),但通过摊还分析能得出:n次push_back的总扩容开销(包括内存分配和元素拷贝)是O(n)——因为每个元素最多被拷贝log₂(n)次,所有元素的拷贝次数加起来是n + n/2 + n/4 + ... ≈ 2n,属于线性量级。
分析代码的内存变化过程
先理清楚这段代码里vector的size和capacity是怎么变的:
std::vector<int> data; for (int i = 0; i < N; ++i) { // 加2N个元素:size从S变成S+2N for (int k = 0; k < 2 * N; ++k) data.push_back(k); // 删N个元素:size从S+2N变成S+N for (int k = 0; k < N; ++k) data.pop_back(); }
- 一开始data是空的,size和capacity都是0;
- 第一次外层循环结束后,size变成N,capacity至少是2N(因为要装下2N个元素,会触发多次扩容直到容量够);
- 第二次循环结束后,size变成2N,capacity至少是4N(push到3N的时候容量不够,会扩容到4N);
- 以此类推,第N次循环结束后,size会达到N²,capacity会是大于等于N²的最小2的幂。
计算alloc/realloc/new的总时间复杂度
核心就是算所有扩容操作的总开销:
push_back的总次数:N次外层循环 × 每次2N个 = 2N²次;- 根据摊还分析的结论,2N²次
push_back的总扩容开销(内存分配+元素拷贝)是O(2N²)=O(N²); - 至于
pop_back,vector默认不会主动缩容,所以不会触发任何内存分配或释放操作,没啥开销。
为什么你的理解有偏差?
你可能误以为每次外层循环后vector的size会回到初始状态,但实际上每次循环结束后,size都会净增N个元素(加2N减N),经过N次循环后,vector的总size会达到N²,对应的push_back总次数是2N²,这才是计算扩容开销的关键基础。
总结:当N极大时,这段代码中alloc/realloc/new操作的时间复杂度是O(N²)。
内容的提问来源于stack exchange,提问作者Hmmman
相关产品推荐
相关产品推荐

