目录
- vector介绍
- vector的使用
- vector的定义
- vector接口函数
- 构造函数和赋值重载
- 迭代器
- 元素访问
- vector容量相关函数
- vector增加 删除 修改操作
- 关系操作符
vector介绍
- vector是可变大小数组的序列容器。
- 像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
思考一个问题:可以用
vector<char>
替代string
吗?
答案是不能:原因有二
1.结构不同,string要求最后又'\0'
,为了更好的兼容C,string的函数都会对'\0'
处理,但是vector的函数不会
2.string中又许多独特的接口函数
vector的使用
vector的定义
template < class T, class Alloc = allocator<T> > class vector;
vector的定义是模板的形式,因为会有不同类型的模板
有2个模板参数,
class T
指的是元素的类型,在类中有别名为value_type
,因为类中进行了typedef T value_type
class Alloc = allocator<T>
是空间配置器(内存池),有缺省值,通常我们不用传这个参数
vector接口函数
构造函数和赋值重载
构造函数 | 说明 |
---|---|
vector() | 无参构造 |
vector(size_type n,const value_type& val = value_type()) | 构造并初始化n个val |
vector (const vector& x); | 拷贝构造 |
vector (InputIterator first, InputIterator last); | 使用迭代器进行初始化构造 |
vector()
无参构造我们不必多说
vector(size_type n,const value_type& val = value_type())
,value_type
就是T
,是typedef
出来的
val
的缺省值value_type()
其实就是容器中元素类型的构造函数,以无参构造出的值为缺省值
这里T的类型假如是自定义类型
Date
,那么缺省值是Date()
,就是默认构造函数,我们都可以理解
如果T类型 为内置类型,比如int
,那么int()
是什么意思呢?
这里其实是C++中的优化,int()其实会就是0
void test1()
{vector<int> v(5, 2); //22222
}
vector (const vector& x);
拷贝构造,也没什么多说的
vector (InputIterator first, InputIterator last);
,这里的迭代器可以是自己容器的,也可以是其他容器的,甚至可以是数组的
void test1()
{vector<int> v1(5, 98); vector<int> v2(v1.begin(), v1.end());//相同类型的迭代器for (auto e : v2){cout << e << " "; e++;}//输出98 98 98 98 98cout << endl;vector<char> v3(v1.begin(), v1.end());//相同容器不同元素类型的迭代器for (auto e : v3){cout << e << " ";e++;}//输出b b b b bcout << endl;int nums[] = { 1,2,3,4,5,6 };vector<int> v4(nums, nums + sizeof(nums) / sizeof(int));//数组for (auto e : v4){cout << e << " ";e++;}//输出1 2 3 4 5 6 cout << endl;
}
赋值重载
vector& operator= (const vector& x);
void test2()
{vector<char> v1(10, 'x');vector<char> v2;v1 = v2;//xxxxxxxxxx
}
迭代器
这里的迭代器也是指针
用法和前面的string的迭代器类似
void test2()
{int nums[] = { 1,2,3,4,5,6,7,8,9,10 };vector<int> v(nums, nums + 10);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}//1 2 3 4 5 6 7 8 9 10cout << endl;vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";rit++;}//10 9 8 7 6 5 4 3 2 1cout << endl;const vector<int> cv(nums, nums + 10);vector<int>::const_iterator cit = cv.cbegin();while (cit != cv.cend()){cout << *cit << " ";cit++;}//1 2 3 4 5 6 7 8 9 10cout << endl;vector<int>::const_reverse_iterator crit = cv.crbegin();while (crit != cv.crend()){cout << *crit << " ";crit++;}//10 9 8 7 6 5 4 3 2 1cout << endl;
}
元素访问
operator[]
vector
中也重载了[]
reference operator[] (size_type n);//读写
const_reference operator[] (size_type n) const;//只读
用法和string::operator[]一样
还是会assert断言判断是否下标越界
at
reference at (size_type n);
const_reference at (size_type n) const;
用法和at
相似
如果下标越界,就会抛出异常
front和back
front
返回第一个元素
back
返回最后一个元素
这两个函数不常用,完全可以用[]
替代: v.front()–>v[0] v.back()–>v[v.size()-1]
data
value_type* data() noexcept;
const value_type* data() const noexcept;
返回指向内存数组的直接指针
vector容量相关函数
函数 | 说明 |
---|---|
size | 获取数据个数 |
max_size | 获取最大数据个数 |
capacity | 获取容量大小 |
empty | 判空 |
shrink_to_fit | 缩减至适合容量 |
resize | 调整size |
reserve | 调整capacity |
这几个函数在string也都有,用法都相似
这里只有reserve
函数和string中略有区别
如果 n 大于当前的矢量容量,函数会使容器重新分配存储空间,将容量增加到 n(或更大)。
在所有其他情况下,函数调用不会导致重新分配,向量容量也不会受到影响。
这里与string中的reserve不同,如果n<capacity(),string中的reserve可能会减少,取决于编译器
但是vector中的n<capacity()也不会减少capacity
capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
但是也不要固化的认为,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
resize会影响size()和capacity()
下面有一个情况,我们先用无参构造出一个vector<int>
类型对象,再用reserve函数开出空间,如果我们用[]
去赋值会发生什么呢?
void test3()
{vector<int> v;v.reserve(20);v[0] = 1;v[1] = 2;
}
答案是,程序会报错
原因是,虽然用reserve(20)开辟了20个空间,但是此时size()
为0
然后我们再通过[]
去赋值,operator[]
函数内部有assert
断言,这里就会报错
所以像上面的那个情况,需要使用resize
函数,resize
既可以改变size
也可以改变capacity
void test3()
{vector<int> v;v.resize(20);v[0] = 1;v[1] = 2;
}
vector增加 删除 修改操作
push_back
void push_back (const value_type& val);
作用:尾插一个元素
pop_back
void pop_back();
作用:删除最后一个元素
insert
iterator insert (iterator position, const value_type& val);void insert (iterator position, size_type n, const value_type& val);template <class InputIterator>void insert (iterator position, InputIterator first, InputIterator last);
前面string类型的insert函数,都是在size_t类型的pos位置插入
而vector中的insert都是在迭代器position位置处插入
iterator insert (iterator position, const value_type& val)
,在position迭代器位置处插入val
void insert (iterator position, size_type n, const value_type& val)
,在position迭代器位置处插入n
个val
template <class InputIterator> void insert (iterator position, InputIterator first, InputIterator last);
在迭代器position位置处插入[frist,last)迭代器区间中的内容
void test4()
{vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);v.push_back(7);v.insert(v.begin() + 3,100);//0 1 2 (100) 3 4 5 6 7v.insert(v.begin(), 2, 10);//(10 10) 0 1 2 100 3 4 5 6 7int num[] = { 12,13,14,15 };v.insert(v.begin() + 1, num, num + 4);//10 (12 13 14 15) 10 0 1 2 100 3 4 5 6 7for (auto e : v){cout << e<<" ";e++;}
}
erase
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
iterator erase (iterator position)
删除迭代器position位置处元素
iterator erase (iterator first, iterator last)
删除[first,last)迭代器区间中的内容
void test5()
{vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);v.push_back(7);//0 1 2 3 4 5 6 7v.erase(v.begin()); //1 2 3 4 5 6 7v.erase(v.begin() + 2, v.end());//1 2
}
上面的
erase
和insert
会涉及到迭代器失效,迭代器失效我们之后会进行了解
swap
void swap (vector& x);
交换两个vector的数据空间
clear
void clear();
清除内容
使size()值变为0,不改变capacity()的值
关系操作符
vector中也支持各种关系操作符的重载,这些函数为非成员函数重载
关系操作符对于string很实用,但是关系操作符对于vector用处不大