STL—— Vector容器
- Vector
- 1、定义
- 2、数据结构
- 3、vector成倍扩容过程及部分源码
- 3.1、扩容条件
- 3.2、扩容步骤(3步)
- 3.3、扩容操作部分源码( insert_aux ) ——push_back() + insert()
- 4、vector基本用法
- 4.1 vector容器构造函数
- 4.2 增加函数(push_back + insert)
- 4.3 删除函数
- 4.4 其他常用
- 4.5 vector常用算法
- 参考
Vector
#include<vector>
1、定义
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622193806629.png)
vector占用一块连续分配的内存,一种可以存储任意类型的动态数组,与array不同的地方就是:数组是静态分配空间,一旦分配了空间的大小,就不可再改变了;而vector是动态分配空间,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量。
属性:
- 1、支持随机访问
- 2、末尾相对快速地添加/删除元素的方法(O(1)时间复杂度)
- 3、动态内存分配(成倍扩容(面试热点))
2、数据结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622194350612.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
template <class T, class Alloc = alloc>
class vector
{
public:
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:
typedef simple_alloc <value_type, Alloc> data_allocator;
iterator start;
iterator finish;
iterator end_of_storage;
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() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
reference front() { return *begin(); }
reference back() { return *(end() - 1); }
...
};
vector数据结构如下,通过三个迭代器start, finish, end_of_storage的系列public接口,可很好地完成数据存储、溢出判断(iter >= iv.end())、大小、容量(容量与大小不等,以免不断申请空间耗费资源)、重载操作符[]、判空、最前元素、最后元素等等。
vector 原始对象本身大小为12(32位)对应3个指针。
iterator start;
iterator finish;
iterator end_of_storage;
在VS中可用sizeof(vector)来输出查看。
3、vector成倍扩容过程及部分源码
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622200250212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622203838884.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素,vector动态增加大小时,并不是在原空间之后持续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大的空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。
3.1、扩容条件
size==capacity
- size:实际所包含的元素个数
- capacity:容器的容量,指的是在不分配更多内存的情况下,容器可以保存的最多元素个数
3.2、扩容步骤(3步)
- 1、完全弃用现有的内存空间,成倍申请更大的内存空间;
- 2、将旧内存空间中的数据,按原有顺序移动到新的内存空间中;
- 3、最后将旧的内存空间释放。
面试热点:
vector 容器在进行扩容后,与其相关的指针、引用以及迭代器可能会失效。
start不再指向相同的地址,扩大空间是新请新的更大的空间,因而不仅是start迭代器,其它指向空间变化前vector的迭代器都将失效
3.3、扩容操作部分源码( insert_aux ) ——push_back() + insert()
- push_back()
push_back()将新元素插入于vector尾端时,该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器finish,使vector增大。如果没有空间则扩充空间(重新配置所需空间、所有元素移动到新空间、释放原空间)。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622210118967.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
void push_back(const T& x)
{
if (finish != end_of_storage)
{
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
- push_back()
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200622213255106.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
iterator insert(iterator position, const T& x)
{
size_type n = position - begin();
if (finish != end_of_storage && position == end())
{
construct(finish, x);
++finish;
}
else
insert_aux(position, x);
return begin() + n;
}
- insert_aux
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020062221412692.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pNVzE0MDc=,size_16,color_FFFFFF,t_70)
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x)
{
if (finish = != end_of_storage)
{
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 * ols_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
try {
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish);
}
catch (...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
destory(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
template<class BidirectionalIterator1, class BidirectionalIterator2>
BidirectionalIterator2 copy_backward ( BidirectionalIterator1 first,
BidirectionalIterator1 last,
BidirectionalIterator2 result )
{
while (last != first) *(--result) = *(--last);
return result;
}
4、vector基本用法
参考
4.1 vector容器构造函数
vector():创建一个空vector
vector(int nSize):创建一个vector,元素个数为nSize
vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
vector(const vector&):复制构造函数
vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
实例:
vector<int> vecInt;
vector<float> vecFloat;
vector<vector<int>> vec;
class A
{
};
vector<A> vecA
struct B
{空结构体}
vector<B> vecB
vector<int> vecIntA(3);
vector<int> vecIntB(3,9);
vector<int> vecIntC(vecIntB);
int iArray[]={2,4,6};
vector<int> vecIntD(iArray,iArray+3);
4.2 增加函数(push_back + insert)
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
vector<int> vecIntA;
vecIntA.push_back(1);
vector<int> vecIntB;
vector<int>::iterator it;
vecIntB.insert(it=vecIntB.begin(),888);
vector<int> vecIntC;
vector<int>::iterator it;
vecIntC.insert(it=vecIntC.begin(),3,888);
4.3 删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
vecIntA.pop_back();
vector<int> vecIntA;
vecIntA.erase(vecIntA.begin()+4);
vecIntA.erase(vecIntA.begin()+1,vecIntA.begin()+5);
4.4 其他常用
判断容器是否为空:vec.empty()
传回第一个数据:vec.front();
清空:vec.clear();
向量数量:vec.size();
4.5 vector常用算法
- 使用reverse将元素翻转:
将元素翻转(在vector中,如果一个函数中需要两个迭代器,一般后一个都不包含)。
#include<algorithm>,
reverse(vec.begin(),vec.end());
#include<algorithm>
sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大)。
可以通过重写排序比较函数按照降序比较,如下:
bool Comp(const int &a,const int &b)
{
return a>b;
}
调用时:
sort(vec.begin(),vec.end(),Comp),这样就降序排序。
源码参考
参考
1、https://www.cnblogs.com/sooner/p/3273395.html
2、https://blog.csdn.net/wizardtoh/article/details/82532236
3、https://blog.csdn.net/u011028345/article/details/60475566
4、《STL源码剖析》
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)