vector扩容
来源:互联网 发布:linux c一站式编程pdf 编辑:程序博客网 时间:2024/05/16 14:18
vector向量容器相当于一个动态的数组,当向向量容器中不断加入元素,若超过容器本身的大小限制,vector会自动拓展大小,在这过程中涉及到内存的分配和回收。在veector中有size()和capacity()函数。size()函数是指返回当前容器中的元素个数,对应的resize(size_type)会在容器尾添加或删除一些元素,来调整容器中实际的内容,使容器达到指定的大小。capacity()指最少要多少元素才会使其容量重新分配,对应的reserve(size_type new_size)会置这个capacity值,使它不小于所指定的new_size。VS2012是以1.5倍扩容,gcc是以两倍扩容
int main(){ vector<int> vec; for(int i=0;i<50;++i) { cout<<vec.size()<<" "<<vec.capacity()<<endl;vec.push_back(i); }}VS2012下:
gcc下:
可以看出在VS2012下,vector一次增长1.5倍
在gcc下,vector一次增长2倍(STL中的vector一次增长2倍)
vector大小拓展过程?
1)为需要的新容量分配足够的内存;
2)将元素从原来的内存拷贝到新内存中;
3)销毁原来内存中的元素;
4)归还原来的内存。
vector为什么要成倍的扩容而不是一次增加一个固定大小的容量呢?
成倍扩容,vector中push_back操作的时间复杂度为O(1)。
一次增加一个固定大小的容量,vector中push_back操作的时间复杂度为O(n)。对比就可以发现,采用成倍方式方式扩容,时间复杂度更小。
vector为什么是以两倍的方式扩容而不是三倍四倍,或者其他方式呢?
为了防止申请内存浪费,较多使用2倍和1.5倍,而1.5倍的增长方式可以更好的实现对内存的重复利用。减小堆空间浪费
如何减小vector初始内存分配频繁 ?
调用reserve(),reserve只开辟内存,resize()不仅开辟内存,还增加了元素个数。
源码如下:
template<class T,class Alloc = alloc>class vector{public: //vector的嵌套型别定义 typedef T value_type; typedef value_type * pointer; typedef value_type * iterator; typedef value_type & reference; typedef size_t size_type; typedef ptrdiff_t difference_type;protected: //以下,simple_alloc是SGI STL的空间配置器 typedef simple_alloc<value_type,Alloc> data_allocator; iterator start; //表示目前使用空间的头 iterator finish; //表示目前使用空间的尾 iterator end_of_storage; //表示目前可用空间的尾 void insert_aux(iterator position,const T&x); //当目前空间不够用,扩容 void deallocate() { if(start) { data_allocator::deallocate(start,end_of_storage-start); } } //填充并予以初始化 void fill_initialize(size_type n,const T& value) { start = allocate_and_fill(n,value); finish = start + n; end_of_storage = finish; }public: iterator begin() {return start;} iterator end() {return finish;} size_type size()const {return size_type(end()-begin());} size_type capacity()const {return size_type(end_of_storage-begin());} bool empty()cosnt {return begin()==end();} reference operator[](size_type n) { retutrn *begin() + n;} vector():start(0),finish(0),end_of_storage(0) {} //构造函数,允许指定vector大小n和初值value vector(size_type n,const T& value) { fill_initialize(n,value);} vector(int n,const T& value) { fill_initialize(n,value);} vector(long n,const T& value) { fill_initialize(n,value);} explicit vector(size_type n) { fill_initialize(n,T());} ~vector() { destroy(start,finish); //全局函数 可看上一篇空间配置器 deallocate(); //这是vector的一个member function } reference front() {return *begin();} //第一个元素 reference back() {return *(end() - 1);} //最后一个元素 /*将新元素插入于vector尾端时,该函数首先检查是否还有备用空间,如果有就直接 在备用空间上构造元素,并调整迭代器finish,使vector变大,如果没有备用空间了, 就扩充空间(重新配置,移动数据,释放原空间)*/ void push_back(const T& x) //将元素插入至最尾端 { if(finish != end_of_storage)//还有备用空间 { construct(finish,x); //全局函数 可看上一篇空间配置器 ++finish; //调整水位高度 } else //已无备用空间 { insert_aux(end(),x); } } void insert_aux(iterator position,const T& x) { if(finish != end_of_storage) //还有备用空间 { //在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值 construct(finish,*(finish-1)); ++finish; //调整水位高度 T x_copy = x; copy_backward(position,finish-2,finish-1); *position = x_copy; } else //已无备用空间 { const size_type old_size = size(); const size_type len = old_size != 0 ? 2*old_size : 1; //以上配置原则:如果原大小为0,则配置1个元素大小; //如果原大小不为0,则配置原大小的两倍 //前半段用来放置原数据,后半段准备用来放置新数据 iterator new_start = data_allocator::allocate(len); //实际配置 iterator new_finish = new_start; try { //将原来vector的内容拷贝到新vector new_finish = uninitialized_copy(start,position,new_start); //为新元素设定初值x construct(new_finish,x); //调整水位 ++new_finish; //将原vector的备用空间中的内容也拷贝过来 new_finish = uninitialized_copy(position,finish,new_finish); } catch(...) { destroy(new_start,new_finish); data_allocator::deallocate(new_start,len); throw; } //析构并释放原vector destroy(begin(),end()); deallocate(); //调整迭代器,指向新vector start = new_start; finish = new_finish; end_of_storage = new_start + len; } } void pop_back() //将最尾端元素取出 { --finish; //将尾端标记往前移一格,表示已放弃尾端元素 destroy(finish); //全局函数 可看上一篇空间配置器 } //清除[first,last]中的所有元素 iterator erase(iterator first,iterator last) { iterator i = copy(last,finish,first); destroy(i,finish); finsh = finish - (last - first); return first; } //清除某位置上的元素 iterator erase(iterator position) { if(position + 1 != end()) copy(position+1,finish,position);//后续元素往前移动 --finish; destroy(finish); return position; } void resize(size_type new_size,const T&x) { if(new_size < size()) erase(begin()+new_size,end()); else inser(end(),new_size-size(),x); } void resize(size_type new_size) {resize(new_size,T());} void clear() {erase(begin(),end());}protected: //配置后填充 iterator allocate_and_fill(size_type n,cosnt T&x) { iterator result = data_allocator::allocate(n); //表示配置n个元素空间 //会根据第一参数的型别特性,决定使用算法fill_n()或 //反复调用construct()来完成任务 uninitialized_fill_n(result,n,x); return result; }};
- vector扩容
- vector的自动扩容
- vector扩容原理说明
- c++STL vector扩容过程
- vector扩容问题源代码剖析
- ArrayList和Vector的扩容机制
- ArrayList、Vector、HashMap、HashTable是如何扩容
- ArrayList、Vector、HashMap、HashTable是如何扩容
- ArrayList和Vector的扩容机制
- ArrayList和Vector的扩容机制
- vector扩容2倍与1.5倍
- ArrayList和Vector的扩容机制
- ArrayList、Vector、HashMap、HashTable是如何扩容
- StringBuffer、StringBuilder、ArrayList、Vector、HashMap、HashTable是如何扩容的
- Java和Android中ArrayList与Vector的扩容比较
- HashMap、HashTable和Vector的存储扩容解析
- ArrayList和Vector区别以及其扩容机制
- 扩容
- 基于日志的同步数据一致性和实时抽取
- Django自定义标签实现多级评论
- 图解25匹马的选马问题
- pandas把所有大于0的数设置为1
- CF 454B Little Pony and Sort by Shift KMP算法简单运用
- vector扩容
- python爬虫OS X环境搭建
- eclipse clean 之后无法运行的问题
- Spring Boot属性配置文件详解
- 作业7
- Asp.net中SessionState相关配置
- 2017.10.19 第九天总结
- 167. Two Sum II
- 菜鸟学Java--包装类及其用法