(1)std::vector 是 STL 提供的 内存连续的、可变长度 的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。
(2)Vectors 包含着一系列连续存储的元素,其行为和数组类似。访问Vector中的任意元素或从末尾添加元素都可以在常量级时间复杂度内完成,而查找特定值的元素所处的位置或是在Vector中插入元素则是线性时间复杂度。
2、为什么要使用 vector?
1、vector 可以动态分配内存
很多时候我们不能提前开好那么大的空间(eg:预处理 1~n 中所有数的约数)。尽管我们能知道数据总量在空间允许的级别,但是单份数据还可能非常大,这种时候我们就需要 vector 来把内存占用量控制在合适的范围内。vector 还支持动态扩容,在内存非常紧张的时候这个特性就能派上用场了。
2、vector 重写了比较运算符及赋值运算符
vector 重载了六个比较运算符,以字典序实现,这使得我们可以方便的判断两个容器是否相等(复杂度与容器大小成线性关系)。例如可以利用 vector 实现字符串比较(当然,还是用 std::string 会更快更方便)。另外 vector 也重载了赋值运算符,使得数组拷贝更加方便。
3、vector 便利的初始化
由于 vector 重载了 = 运算符,所以我们可以方便的初始化。此外从 C++11 起 vector 还支持 列表初始化,例如 vector data {1, 2, 3};。
3、vector 的创建
// 1. 创建空vector; 常数复杂度
vector v0;
// 1+. 这句代码可以使得向vector中插入前3个元素时,保证常数时间复杂度
v0.reserve(3);
// 2. 创建一个初始空间为3的vector,其元素的默认值是0; 线性复杂度
vector v1(3);
// 3. 创建一个初始空间为3的vector,其元素的默认值是2; 线性复杂度
vector v2(3, 2);
// 4. 创建一个初始空间为3的vector,其元素的默认值是1,
// 并且使用v2的空间配置器; 线性复杂度
vector v3(3, 1, v2.get_allocator());
// 5. 创建一个v2的拷贝vector v4, 其内容元素和v2一样; 线性复杂度
vector v4(v2);
// 6. 创建一个v4的拷贝vector v5,其内容是{v4[1], v4[2]}; 线性复杂度
vector v5(v4.begin() + 1, v4.begin() + 3);
// 7. 移动v2到新创建的vector v6,不发生拷贝; 常数复杂度; 需要 C++11
vector v6(std::move(v2)); // 或者 v6 = std::move(v2);
4、元素访问
-
at()
v.at(pos) 返回容器中下标为 pos 的引用。如果数组越界抛出 std::out_of_range 类型的异常。
-
operator[]
v[pos] 返回容器中下标为 pos 的引用。不执行越界检查。
-
front()
v.front() 返回首元素的引用。
-
back()
v.back() 返回末尾元素的引用。
-
data()
v.data() 返回指向数组第一个元素的指针。
5、迭代器
-
begin()/cbegin()
返回指向首元素的迭代器,其中 *begin = front。
-
end()/cend()
返回指向数组尾端占位符的迭代器,注意是没有元素的。
-
rbegin()/crbegin()
返回指向逆向数组的首元素的逆向迭代器,可以理解为正向容器的末元素。
-
rend()/crend()
返回指向逆向数组末元素后一位置的迭代器,对应容器首的前一个位置,没有元素。
6、与长度相关:
1、vector 可以动态分配内存
很多时候我们不能提前开好那么大的空间(eg:预处理 1~n 中所有数的约数)。尽管我们能知道数据总量在空间允许的级别,但是单份数据还可能非常大,这种时候我们就需要 vector 来把内存占用量控制在合适的范围内。vector 还支持动态扩容,在内存非常紧张的时候这个特性就能派上用场了。
2、vector 重写了比较运算符及赋值运算符
vector 重载了六个比较运算符,以字典序实现,这使得我们可以方便的判断两个容器是否相等(复杂度与容器大小成线性关系)。例如可以利用 vector
3、vector 便利的初始化
由于 vector 重载了 = 运算符,所以我们可以方便的初始化。此外从 C++11 起 vector 还支持 列表初始化,例如 vector
-
at()
v.at(pos) 返回容器中下标为 pos 的引用。如果数组越界抛出 std::out_of_range 类型的异常。
-
operator[]
v[pos] 返回容器中下标为 pos 的引用。不执行越界检查。
-
front()
v.front() 返回首元素的引用。
-
back()
v.back() 返回末尾元素的引用。
-
data()
v.data() 返回指向数组第一个元素的指针。
-
begin()/cbegin()
返回指向首元素的迭代器,其中 *begin = front。
-
end()/cend()
返回指向数组尾端占位符的迭代器,注意是没有元素的。
-
rbegin()/crbegin()
返回指向逆向数组的首元素的逆向迭代器,可以理解为正向容器的末元素。
-
rend()/crend()
返回指向逆向数组末元素后一位置的迭代器,对应容器首的前一个位置,没有元素。
empty() 返回一个 bool 值,即 v.begin() == v.end(),true 为空,false 为非空。
size() 返回容器长度(元素数量),即 std::distance(v.begin(), v.end())。
resize() 改变 vector 的长度,多退少补。补充元素可以由参数指定。
max_size() 返回容器的最大可能长度。
与容量相关:
reserve() 使得 vector 预留一定的内存空间,避免不必要的内存拷贝。
capacity() 返回容器的容量,即不发生拷贝的情况下容器的长度上限。
shrink_to_fit() 使得 vector 的容量与长度一致,多退但不会少。
7、元素增删及修改
- clear() 清除所有元素
- insert() 支持在某个迭代器位置插入元素、可以插入多个。复杂度与 pos 距离末尾长度成线性而非常数的
- erase() 删除某个迭代器或者区间的元素,返回最后被删除的迭代器。复杂度与 insert 一致。
- push_back() 在末尾插入一个元素,均摊复杂度为 常数,最坏为线性复杂度。
- pop_back() 删除末尾元素,常数复杂度。
- swap() 与另一个容器进行交换,此操作是 常数复杂度 而非线性的。
8、代码示例:
- clear() 清除所有元素
- insert() 支持在某个迭代器位置插入元素、可以插入多个。复杂度与 pos 距离末尾长度成线性而非常数的
- erase() 删除某个迭代器或者区间的元素,返回最后被删除的迭代器。复杂度与 insert 一致。
- push_back() 在末尾插入一个元素,均摊复杂度为 常数,最坏为线性复杂度。
- pop_back() 删除末尾元素,常数复杂度。
- swap() 与另一个容器进行交换,此操作是 常数复杂度 而非线性的。
#include#include using namespace std; int main() { vector v0;//创建一个v0向量 v0.reserve(3);//设置v0最小的元素容纳数量 for(int i = 1; i <= 10; i++)//将1~10的数字填入向量中 v0.push_back(i);//在v0最后添加一个元素 cout<<"first element :" << v0.front() << endl;//返回v0第一个元素 cout<< "last element :" << v0.back()< 运行结果:
3、依次从头删除(迭代器)
#include#include using namespace std; int main() { vector v0;//创建一个v0向量 for (int i = 1; i <= 10; i++)//将1~10的数字填入向量中 v0.push_back(i);//在v0最后添加一个元素 int size = v0.size();//设置v0长度 vector ::iterator startIt; vector ::iterator tempIt; for (int i = 0; i < size; i++) { startIt = v0.begin(); v0.erase(startIt); //Display the vector for (tempIt = v0.begin(); tempIt != v0.end(); tempIt++) { cout << *tempIt; } cout << endl; } return 0; } 程序运行结果:



