一、vector的介绍
说的简单点:
vector是可以动态增长的数组容器
vector
是表示可变大小数组的序列容器。- 就像数组一样,
vector
也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector
的元素进行访问,和数组一样高效。- 本质讲,
vector
使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。vector
分配空间策略:vector
会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。。- 因此,
vector
占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。- 与其它动态序列容器相比(
deques, lists and forward_lists
), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists
和forward_lists
统一的迭代器和引用更好。
如果想要了解更多请猛戳这里
二、vector的使用
2.1vector构造函数
构造函数 | 功能 |
---|---|
vector() |
无参构造 |
vector(size_type n, const value_type& val = value_type()) |
构造并初始化n个val |
vector (const vector& x) (重点) |
拷贝构造 |
vector (InputIterator fifirst, InputIterator last) |
使用迭代器进行初始化构造 |
void test1()
{
vector<int> v1;//无参的构造用的最多
vector<int> v2(10,1);//用10个1来初始化
vector<int> v3(v2.begin(),v2.end());//用一段迭代器区间去初始化
vector<int> v4(v3);//拷贝构造
string s("hello");
vector<char> v5(s.begin(), s.end());//不同STL的迭代器区间也可以初始化
}
结果展示:
打开监视窗口观察,确实初始化好了
问题:
对于下面这种情况:
string s; 和 vector<char> v;
是不是差不多呢?能不能相互替代呢?
不行的!因为string末尾带着
\0
,而且string提供了一些专门的字符串相关的接口函数,比如:operator+=,c_str,find等等函数
2.2迭代器的使用
iterator的使用 | 功能 |
---|---|
begin+end |
获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator |
rebegin+rend |
获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置reverse_iterator |
//vector中如何遍历
void test2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//下标[]遍历
for (size_t i = 0; i < v.size(); ++i)
{
v[i] += 1;
cout << v[i] << " ";
}
cout << endl;
//迭代器
vector<int>::iterator it=v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//反向迭代器
vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
++rit;
}
//范围for
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
2.3空间增长问题
容量函数 | 功能 |
---|---|
size( ) |
获取数据个数 |
capacity( ) |
获取容量大小 |
empty( ) |
判空 |
resize( ) |
改变size |
reserve( ) |
改变capacity |
void test3()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
cout << v.size() << endl;
cout << v.capacity() << endl;
cout << v.empty() << endl;
cout << endl;
v.reserve(100);//改变capacity
cout << v.size() << endl;
cout << v.capacity() << endl;
cout << v.empty() << endl;
cout << endl;
v.resize(10,1);//改变size,默认给上缺省值0,它可以 扩容+初始化 或者 删除数据
cout << v.size() << endl;
cout << v.capacity() << endl;
cout << v.empty() << endl;
cout << endl;
v.resize(2);
cout << v.size() << endl;
cout << v.capacity() << endl;
cout << v.empty() << endl;
cout << endl;
}
结果展示:
总结:
- capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,顺序表增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
- reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
- resize在开空间的同时还会进行初始化,影响size。
2.4增删查改问题
函数 | 功能 |
---|---|
push_back( ) |
尾插 |
pop_back( ) |
尾删 |
insert( ) |
在pos之前插入 |
erase( ) |
删除 |
swap( ) |
交换两个vector的数据空间 |
operator[ ]常用 |
下标位置访问 |
find( ) |
这个是算法库里面实现的查找(algorithm ),不是vector的成员函数 |
void test4()
{
vector<int> v;
//push_back尾插
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//find查找
vector<int>::iterator ret = find(v.begin(), v.end(),3);
auto ret1 = find(v.begin(), v.end(), 3);
//可以用auto替换
if (ret != v.end())
{
cout << "找到了" << endl;
}
v.insert(ret, 100);
for (auto e : v)
{
cout << e << " ";
}
vector<int>::iterator pos = find(v.begin(), v.end(), 1);
if (pos != v.end())//判断数据是否合法
{
//erase删除
v.erase(pos);
}
cout << endl;
}
结果演示:
operator[ ] 和范围for是vector中常用的遍历手段
// vector使用这两种遍历方式是比较便捷的。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int a[] = {
1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a) / sizeof(int));
// 通过[]读写第0个位置。
v[0] = 10;
cout << v[0] << endl;
// 通过[i]的方式遍历vector
for (size_t i = 0; i < v.size(); ++i)
cout << v[i] << " ";
cout << endl;
vector<int> swapv;
swapv.swap(v);
cout << "v data:";
for (size_t i = 0; i < v.size(); ++i)
cout << v[i] << " ";
cout << endl;
cout << "swapv data:";
for (size_t i = 0; i < swapv.size(); ++i)
cout << swapv[i] << " ";
cout << endl;
// C++11支持的新式范围for遍历
for (auto x : v)
cout << x << " ";
cout << endl;
return 0;
}
说明:vector是支持迭代器的,还可以用范围for对vector进行遍历,支持迭代器就支持范围for,因为在编译时编译器会自动将范围for替换为迭代器遍历的形式。