STL学习笔记--4序列式容器之vector
Posted chengyu779394084
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL学习笔记--4序列式容器之vector相关的知识,希望对你有一定的参考价值。
常见的数据结构:array数组,list链表,tree树,stack栈,queue队列,hash table散列表,set集合,map映射……
根据数据在容器中的排列分为:序列式sequence和关联式associative。
序列式容器之vector
1、vector VS array:
- array是静态空间,一旦配置则无法改变;
- vector是动态空间,随着元素的加入,内部机制会自动扩充新的空间来容纳新的元素。
实现技术:对大小的控制和重新配置时的数据移动效率。
扩充空间:配置新空间、数据移动、释放旧空间。
2、定义摘要:
在SGI中,#include<stl_vector.h>
在STl标准中只需要#include<vector>
template <class T, class Alloc = alloc>
class vector {
public:
//嵌套型别定义
typedef T value_type;
typedef value_type* pointer;
//迭代器类型为随机存取类型
//RandomAccessIterator
typedef value_type* iterator;
typedef value_type& reference;
typedef size_t size_type;
protect:
//方便以元素为单位配置大小
typedef simple_alloc<value_type, Alloc> data_allocator;
//表示目前使用的空间头
iterator start;
//表示目前使用的空间尾
iterator finish;
//表示目前可用的空间尾
iterator end_of_storage;
//插入元素。有备用空间直接插入,无备用空间则进行空间分配
void insert_aux(iterator position, const T& x);
//调用全局deallocate来完成
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() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
//构造函数
//默认构造函数
vector() : start(0), finish(0), end_of_storage(0) {}
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();
}
//第一个元素引用
reference front() { return *begin(); }
//最后一个元素引用
reference back() { return *(end() - 1); }
//push_back,调用了insert_aux
void push_back(const T& x) {
if (finish != end_of_storage) {//还有备用空间
construct(finish, x);
++finish;
}
else//以无备用空间
insert_aux(end(), x);
}
//pop_back()
void pop_back() {
--finish;
destroy(finish);
}
//erase版本一:接受一个迭代器
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
//erase版本二:接受二个迭代器。清除迭代器范围的元素
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
}
//resize():为容器重新定义长度。
//若new_size小于size则,丢弃多余部分
//若new_size大于size则,空出的部分进行T类型的值初始化
void resize(size_type new_size, const T& x) {
if (new_size < size())
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size){resize(new_size, T());}
//clear()清空容器
void clear() { erase(begin(), end()); }
protected:
//配置容器并填满内容,填n个x
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
3、vector迭代器
vector维护的是连续线性空间。支持随机存取,迭代器类型为RandomAccessIterator。
4、vector数据结构
//表示目前使用的空间头
iterator start;
//表示目前使用的空间尾
iterator finish;
//表示目前可用的空间尾
iterator end_of_storage;
vector实际配置的大小总是大于等于客户端需求的大小,以备将来的扩充。
增加新元素时,如果超出当时容量,则容量进行两倍扩充;若两倍容量不足时,则扩充足够大的容量。
容量的扩充需要进行:重新配置、元素移动、释放旧空间。
5、构造和内存管理:
vector缺省使用alloc作为空间配置器;
uninitialized_fill_n()
根据第一个参数的型别特性type traits决定算法使用(__true_type
)fill_n()或是反复调用(__false_type
)construct()来完成。
//push_back,调用了insert_aux
void push_back(const T& x) {
if (finish != end_of_storage) {//还有备用空间
construct(finish, x);
++finish;
}
else//以无备用空间
insert_aux(end(), x);
}
算法实现:insert_aux(end(), x);
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) {//还有备用空间
//在备用空间起始处构造元素,以finish - 1位置处的值作为初值
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
//将[position,finish-2)处的值拷贝到[(finish - 1)-((finish - 2)-(position)),finish - 1)
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else {//无备用空间
const size_type old_size = size();
//确定新构造的空间的长度
//若旧空间为0,则构造1个
//若旧空间非零,则构造旧空间的两倍
const size_type len = old_size != 0 ? 2 * old_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
//旧空间的元素拷贝到新空间
new_finish = uninitialized_copy(start, position, new_start);
//新元素指定为x
construct(new_finish, x);
//调整使用空间大小
++new_finish;
//新元素装入
new_finish = uninitialized_copy(position, finish, new_finish);
}
#ifdef __STL_USE_EXCEPTIONS
//若新空间分配失败,则释放所有新分配的空间
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
#endif /* __STL_USE_EXCEPTIONS */
//释放旧空间
destroy(begin(), end());
deallocate();
//调整迭代器,指向新空间
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
6、元素操作:erase()
两个参数版本,释放局部区间的清除操作示意图:
7、元素操作:insert()
insert(iterator position, size_type n, const T& x)
1、若备用空间大于等于新增元素个数
(end_of_storage-finish) >= n
计算插入点之后现有的元素个数
elems_after=finish-position;
情况一:1)、若**插入点之后的现有元素个数**大于**新增元素个数**
elems_after>n
{
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy);
}
情况二:2)、若**插入点之后的现有元素个数**小于等于**新增元素个数**
elems_after<=n
{
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
2、若备用空间小于新增元素个数
(end_of_storage-finish) < n
1)决定新的长度。旧长度的两倍或旧长度+新增元素个数。
len=old_size+max(old_size,n)
2)配置内存空间
iterator new_start =data_allocator::allocate(len);
iterator new_finish = new_start;
情况三:3)数据元素的移动
{
//旧空间的插入点之前的元素copy到新空间
new_finish = uninitialized_copy(start, position, new_start);
//新增的元素初值为x,填入到新空间
new_finish = uninitialized_fill_n(new_finish, n, x);
//旧空间的插入点之后的元素copy到新空间
new_finish = uninitialized_copy(position, finish, new_finish);
}
3、如果分配新空间出现异常,则销毁新分配的内存,抛出异常
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
#endif /* __STL_USE_EXCEPTIONS */
4、清除并释放旧空间内存
destroy(start, finish);
deallocate();
5、调整迭代器,指向新空间
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
情况一:备用空间充足,且elems_after>n
n=2; elems_after=2; 备用空间end_of_storage-finish=2;
情况二:备用空间充足,且elems_after<=n
n=4; elems_after=2; 备用空间end_of_storage-finish=3;
情况三:备用空间不足容纳新增元素
n=3; 备用空间end_of_storage-finish=2;
以上是关于STL学习笔记--4序列式容器之vector的主要内容,如果未能解决你的问题,请参考以下文章
STL 源码剖析读书笔记四:序列式容器之 dequestackqueue