STL 之 vector
1、vector是表示可变大小数组的序列容器;
2、vector存储元素是采用连续存储空间,可利用下标访问vector中的元素;
3、vector是一个能够存放任意类型的动态数组,能够增加和压缩数据;
4、vector是一个类模板,不是一种数据类型。可用来定义任意多种数据类型。vector类型的每一种都指定了其保存元素的类型。因此vector 等都是数据类型。
vector的定义
1、初始化vector对象
构造函数声明 | 接口说明 |
---|---|
vector< T > v1 | 无参构造 |
vector< T > v2(n, val) | 构造并初始化n个val |
vector< T > v3(v2) | 拷贝构造 |
vector< T > V4(v3.begin(),v3.end()) | 使用迭代器进行初始化构造 |
具体使用
int main()
{
vector<int> v1;//无参构造
vector<int> v2(5, 3);//构造并初始化5个3
vector<int> v3(v2);//拷贝构造v2
vector<int> v4(v3.begin(), v3.end());//迭代器构造v3
system("pause");
return 0;
}
查看输出结果
注意事项:
1、在构造非空vector对象时,必须给出初始化元素的值;
2、在进行拷贝构造时,这两个 vector 对象必须是同一种元素类型。
2、vector iterator 的使用
iterator的使用 | 接口说明 |
---|---|
begin() + end() | 获取第一个元素的位置及最后一个元素的下一个位置 |
rbegin() + rend() | 获取最后一个元素的位置及第一个元素的前一个位置 |
举个栗子:
用下面这列数据说明这几个接口的位置
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
迭代器可以遍历打印vector数组的值,还可以修改数组中元素的值;
还可以利用反向迭代器(reverse_iterator)来遍历打印vector数组元素的值。
打印vector数组
void printvector(vector<int> v)
{
#if 0
//方法一:用范围for遍历打印
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
#elif 0
//方法二:const对象使用const迭代器进行遍历打印
vector<int>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
#endif
//反向迭代器,反向遍历打印
vector<int>::reverse_iterator it = v.rbegin();
while (it != v.rend())
{
cout << *it << " ";
it++;
}
cout << endl;
}
3、vector的空间大小
容量空间 | 接口说明 |
---|---|
size() | vector中元素的个数 |
capacity() | 获取分配空间的大小 |
empty() | vector中没有元素返回true,否则返回false |
resize() | 修改size的大小 |
reserve() | 修改capacity的值 |
注:
size与capacity的区别
size是计算当前vector中元素的个数,即真实占用的空间;
capacity是计算vector预分配的空间大小,即可以存储元素的最大空间大小。
resize与reserve的区别
resize()既要开辟空间也要进行初始化,修改size的大小,容器内的对象内存空间是真正存在的;
reserve()只负责开辟空间,改变预留空间的大小,对象内存空间并不是真实的存在。
capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的
4、vector的增删查改
vector的增删查改 | 接口说明 |
---|---|
push_back() | 尾插 |
pop_back() | 尾删 |
find() | 查找 |
insert() | 在pos前插入 |
erase() | 删除pos位置的数据 |
swap() | 交换两个vector的数据空间 |
operator[] | 中括号重载,向数组一样访问 |
以代码为例
insert的三种方法
int main()
{
vector<int> v = { 2,3,4,5 };
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
#if 0
//v.insert(pos,val); 在pos前插入元素的值val
v.insert(pos, 6);//在pos前插入元素6
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
#elif 0
//v.insert(pos, n, val);//在pos前插入n个val
v.insert(pos, 3, 5);//在pos前插入3个5
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
#endif
vector<int> v2 = { 1,2,3,4,5 };
//v.insert(pos, v2.begin(), v2.end());在pos前插入一段元素的值
v.insert(pos, v2.begin(), v2.end());
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
system("pause");
return 0;
}
erase的两种方法
int main()
{
vector<int> v = { 2,3,4,5 };
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
#if 0
v.erase(pos);//删除pos位置的元素
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
#endif
//v.erase(arr.begin(),arr.end()); 删除数组中的一段元素
v.erase(v.begin() + 2,v.end());
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
system("pause");
return 0;
}
重点:迭代器失效问题
使用insert 和erase时会导致迭代器失效,例如下面这个例子:
int main()
{
vector<int> v = { 2,3,4,6,7,8 };
for (auto &e : v)
{
cout << e << " ";
}
cout << endl;
vector<int>::iterator pos = find(v.begin(), v.end(), 6);
//在pos处删除数据,会导致迭代器失效
//因为把pos处的元素删除后,pos还指向原来的空间,此时的元素已经被删除,
//空间也被释放,从而导致迭代器失效。
v.erase(pos);//删除pos处的元素
cout << *pos << endl;//此时pos位置处的元素不能访问,即迭代器失效
// 在pos位置插入数据,导致pos迭代器失效。
// insert会导致迭代器失效,是因为insert可能会导致增容,
//增容后pos还指向原来的空间,而原来的空间已经释放了。
pos = find(v.begin(), v.end(), 3);
v.insert(pos, 30);
cout << *pos << endl; // 此处会导致非法访问
system("pause");
return 0;
}
总结:
insert导致迭代器失效:insert可能会导致增容,增容后pos还指向原来的空间,而原来的空间已经释放了,从而导致迭代器失效;
erase导致迭代器失效:erase把pos处的元素删除后,pos还指向原来的空间,此时的元素已经被删除,空间也被释放,从而导致迭代器失效。