stackoverflow: Why the inital capacity of vector is increasing with the formula 2^N? 为什么vector的capacity是按照2的指数来长的?(原文+翻译)

原文:https://stackoverflow.com/questions/5232198/about-vectors-growth
翻译:joey

Answer 1:

The rate at which the capacity of a vector grows is implementation dependent. Implementations almost invariably choose exponential growth, in order to meet the amortized constant time requirement for the push_back operation. What amortized constant time means and how exponential growth achieves this is interesting.
vector的容量的增长倍数在不同实现版本的STL里是不同的。但这些实现都选择了指数级的增长,其目的是使push_back()的操作有均摊的O(1)的时间复杂度。通过capacity的指数级的增长,以达到push_back()的均摊的O(1)时间复杂度是很有趣的。

Every time a vector‘s capacity is grown the elements need to be copied. If you ‘amortize‘ this cost out over the lifetime of the vector, it turns out that if you increase the capacity by an exponential factor you end up with an amortized constant cost.
每次vector的capacity增长时,它的所有元素都需要被拷贝一份。如果你把这个vector整个生存周期内的这种开销“均摊”一下,你会发现如果capacity的增长是指数级的话,你会得到一份O(1)时间复杂度的push_back()。

This probably seems a bit odd, so let me explain to you how this works...
这可能听起来有点怪,让我为你解释一下我说的是啥玩意儿…

size: 1 capacity 1 - No elements have been copied, the cost per element for copies is 0.
size: 1 capacity 1 - 不需要拷贝元素,对于每个元素的拷贝开销是0。

size: 2 capacity 2 - When the vector‘s capacity was increased to 2, the first element had to be copied. Average copies per element is 0.5
size: 2 capacity 2 - 当vector的capacity提升至2时,第一个元素需要被拷贝,对于每个元素的拷贝开销是1/2=0.5

size: 3 capacity 4 - When the vector‘s capacity was increased to 4, the first two elements had to be copied. Average copies per element is (2 + 1 + 0) / 3 = 1.
size: 3 capacity 4 - 当vector的capacity提升至4时,最前的两个元素需要被拷贝,对于每个元素的拷贝开销是(2 + 1 + 0) / 3 = 1 (译注:2是指size从2->3时,1是指size从1->2时,0是指size从0->1时,以下类推)

size: 4 capacity 4 - Average copies per element is (2 + 1 + 0 + 0) / 4 = 3 / 4 = 0.75.
size: 4 capacity 4 - 对于每个元素的拷贝开销是(2 + 1 + 0 + 0) / 4 = 3 / 4 = 0.75.

size: 5 capacity 8 - Average copies per element is (3 + 2 + 1 + 1 + 0) / 5 = 7 / 5 = 1.4
size: 5 capacity 8 - 对于每个元素的拷贝开销是(3 + 2 + 1 + 1 + 0) / 5 = 7 / 5 = 1.4

...

size: 8 capacity 8 - Average copies per element is (3 + 2 + 1 + 1 + 0 + 0 + 0 + 0) / 8 = 7 / 8 = 0.875
size: 8 capacity 8 - 对于每个元素的拷贝开销是 (3 + 2 + 1 + 1 + 0 + 0 + 0 + 0) / 8 = 7 / 8 = 0.875

size: 9 capacity 16 - Average copies per element is (4 + 3 + 2 + 2 + 1 + 1 + 1 + 1 + 0) / 9 = 15 / 9 = 1.67
size: 9 capacity 16 - 对于每个元素的拷贝开销是 (4 + 3 + 2 + 2 + 1 + 1 + 1 + 1 + 0) / 9 = 15 / 9 = 1.67

...

size 16 capacity 16 - Average copies per element is 15 / 16 = 0.938
size: 16 capacity 16 - 对于每个元素的拷贝开销是 15 / 16 = 0.938

size 17 capacity 32 - Average copies per element is 31 / 17 = 1.82
size: 17 capacity 32 - 对于每个元素的拷贝开销是 31 / 17 = 1.82

As you can see, every time the capacity jumps, the number of copies goes up by the previous size of the array. But because the array has to double in size before the capacity jumps again, the number of copies per element always stays less than 2.
就像你所看到的那样,每当capacity增长时,拷贝的开销是随着当前的capacity越来越大的,但是因为在vector的size翻倍之前,vector的capacity必须翻倍的缘故,每个元素的拷贝开销始终小于2。(译注:妙啊)

If you increased the capacity by 1.5 * N instead of by 2 * N, you would end up with a very similar effect, except the upper bound on the copies per element would be higher (I think it would be 3).
如果vector的capacity按照1.5增长而不是2倍,你可能会得到一个类似的结果,除了每个元素的拷贝开销可能会更高(我认为可能高达3)。

I suspect an implementation would choose 1.5 over 2 both to save a bit of space, but also because 1.5 is closer to the golden ratio. I have an intuition (that is currently not backed up by any hard data) that a growth rate in line with the golden ratio (because of its relationship to the fibonacci sequence) will prove to be the most efficient growth rate for real-world loads in terms of minimizing both extra space used and time.
我猜测一个STL的实现可能会选择一个1.5~2的倍数来实现节约一些空间。但是因为1.5倍更加接近黄金分割,我有个直觉(虽然还没有任何数据支撑):黄金分割比例会是最优效率的增长率(因为它和斐波拉切数列的关系),以保证最小的时间和空间开销。

原文地址:https://www.cnblogs.com/jo3yzhu/p/11143323.html

时间: 2024-10-05 05:10:06

stackoverflow: Why the inital capacity of vector is increasing with the formula 2^N? 为什么vector的capacity是按照2的指数来长的?(原文+翻译)的相关文章

这里想经过一个小程序研究标准库为 vector 对象提供的内存分配策,因为vector容器比list和deque容器用的很多,而且它的存储方式是连续的

我写一个简单的程序来区分vector容器size()和capacity()函数,这里capacity函数就是为vector容器预留了空间,不需要每次增添元素就要重新分配内存,这样效率上提高了很多,我通过一个间的小程序来研究,下面是程序和运行结果,比较简明可以看出capacity的大小都会比size大,因为size 指容器当前拥有的元素个数:而 capacity 则指容 器在必须分配新存储空间之前可以存储的元素总数.废话不多说,附上代码和运行结果:#include"stdafx.h" #

vector的size和capacity改变时空间分配的过程

当增加新元素(s)时,如果超过当时的容量,则容量会扩充至两倍.如果两倍容量仍不足,就扩张至足够大的容量. 以一个例子来说明: #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int i; vector<int> iv(2,9); cout<<"size = "<<iv.size()&l

STL vector总结(三)Capacity(36)

这里是vector的所有构造方法,成员方法的一些总结,具体的可以详看后面的链接. public member function <vector> std::vector::size C++98 C++11 size_type size() const noexcept; 返回vector中元素的个数. 这个个数是vector中实际存放的元素个数,但不一定必须等于这个vector的容量. Parameters none Return Value. 返回值为元素个数. 原文地址:http://bl

【C++】朝花夕拾——STL vector

STL之vector篇 N久之前是拿C的数组实现过vector中的一些简单功能,什么深拷贝.增删查找之类的,以为vector的实现也就是这样了,现在想想真是...too young too naive...ORZ ====================我是分割线============================= vector属于顺序容器,它的底层实现就是基于array,所以它可以支持随机访问,但是它比array更有效率,因为它动态分配的内存空间. 动态分配的内存空间: 每当vector

STL 之 vector源代码实现

一:vector异常类 Myexcep.h #include<string> #include<iostream> using namespace std; class Myexcep { public: Myexcep() :m_exnote("Get a exception ") {} Myexcep(const string &other){m_exnote = other;} virtual ~Myexcep(){} virtual void s

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

C++ vector 使用

看vector 的使用: #include "stdafx.h" #include <iostream> #include <vector> using namespace std; int main() { vector<long> v; for (long i=0;i<10000;i++) { v.push_back(rand()); } cout << "size = " << v.size()

vector容器用法详解

vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组.像数组一样,vector类也用从0开始的下标表示元素的位置:但和数组不同的是,当vector对象创建后,数组的元素个数会随着vector对象元素个数的增大和缩小而自动变化. vector类常用的函数如下所示: 1.构造函数 vector():创建一个空vector vector(int nSize):创建一个vector,元素个数为nSize vector(int nSize,const t& t):创建一个vector,元

stl容器区别: vector list deque set map及底层实现

在STL中基本容器有: vector.list.deque.set.map set 和map都是无序的保存元素,只能通过它提供的接口对里面的元素进行访问 set :集合, 用来判断某一个元素是不是在一个组里面,使用的比较少 map :映射,相当于字典 ,把一个值映射成另一个值,如果想创建字典的话使用它好了 底层采用的是树型结构,多数使用平衡二叉树实现 ,查找某一值是常数时间,遍历起来效果也不错, 只是每次插入值的时候,会重新构成底层的平衡二叉树,效率有一定影响. vector.list.dequ