Vector的介绍
1.vector是表示可变大小数组的序列容器。
这个是什么意思呢? 还记不记得我们之前学的顺序表? 这个是不是和顺序表很相似啊
如果说还有同学不清楚的话可以试着看这篇文章
初阶数据结构 顺序表的讲解
2.就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
这里我们主要需要注意的就是一点 我们可以使用下标来访问vector
3.本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大
小。
所以说我们一般会按照两倍进行扩容来避免频繁扩容
4.vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存
储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是
对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5.vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增
长。
6.与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末
尾添加和删除元素相对高效。对于其他不在末尾的删除和插入操作,效率更低。比起list和forward_list
统一的迭代器和引用更好。
这个时候我们来总结下 需要知道的是什么呢?
它底层实际上和顺序表差不多 可以使用下标来访问 为了提高效率扩容一般是按照两倍扩容
Vector的使用
定义
定义方式有以下几种
方法一: 构造一个某类型的空容器
vector<int> v1; // 构造一个int类型的空容器
方法二:构造一个含有n个val值的容器
vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2
方式三:拷贝构造
vector<int> v3(v2);
方式四:使用迭代器拷贝
vector<int> v4(v2.begin(), v2.end()); //迭代器拷贝构造
注:使用别的容器的迭代器也可以拷贝(不是vector 以string为例)
string s1("hello world"); vector<char> v5(s1.begin(), s1.end()); // 使用string类的迭代器构造
空间相关
szie
这个函数很简单 返回容器中占用的元素个数
代码和效果图如下
vector<int> v1; // 构造一个int类型的空容器 vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 cout << v2.size() << endl; // 输出v2容器中有效元素个数
capacity
返回当前容器的最大容量 用法和size类似
代码和效果图如下
vector<int> v1; // 构造一个int类型的空容器 vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数
reszie
resize函数可以改变容器的有效元素个数
使用规则是这样子的
1 假设所给值小于当前容器size值 size缩小至所给值
2 假设所给值大于当前容器size值并且小于capacity值 size扩大至所给值 扩大的范围赋值0
3 假设所给值大于当前容器size值并且大于capacity值 先扩容 后面操作和2一样
代码和效果图如下
vector<int> v1; // 构造一个int类型的空容器 vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 cout << v2.size() << endl; // 输出v2容器中有效元素个数 v2.resize(100); // 扩大size到100 cout << v2.size() << endl; // 输出v2容器中有效元素个数
reserve
reserve函数可以改变容器的最大容量
使用规则如下
1 假设所给值小于当前容量值 什么都不做
2 假设所给值大于当前容量值 扩容至所给值
代码和效果图如下
vector<int> v1; // 构造一个int类型的空容器 vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数 v2.reserve(100); // 扩大capacity到100 cout << v2.capacity() << endl; // 输出v2容器中最大能容纳的元素个数
empty
empty函数可以判断容器是否为空
代码和使用效果图如下
void test4() { vector<int> v1; // 构造一个int类型的空容器 cout << v1.empty() << endl; vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 cout << v2.empty() << endl; }
迭代器相关
begin和end
通过begin函数我们可以得到容器中第一个元素的正向迭代器
通过end函数我们可以得到容器中最后一个元素的正向迭代器
下面我们使用这个迭代器来遍历数组
代码和效果图如下
vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 vector<int>::iterator it = v2.begin(); while (it!=v2.end()) { cout << *it << " "; it++; }
rbegin和rend
通过rbegin函数我们可以得到容器中第一个元素的反向迭代器
通过rend函数我们可以得到容器中最后一个元素的正向迭代器
下面我们使用这个迭代器来遍历数组
代码和效果图如下
注意 我们这里正向迭代器和反向迭代器的定义并不相同
vector<int> v2(10, 2); // 构造一个int类型的容器 初始化为10个2 vector<int>::reverse_iterator it = v2.rbegin(); while (it != v2.rend()) { cout << *it << " "; it++; }
增删查改
push_back
我们使用这个函数来向容器中插入一个值
代码和使用效果如下
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
pop_back
我们使用这个函数来向容器中删除一个值
代码和使用效果如下
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.pop_back(); v1.pop_back(); v1.pop_back(); vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
insert
inset 函数有两个用法
一 选择一个位置(迭代器) 选择一个我们要插入的元素
代码和显示效果如下
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.insert(v1.begin(), 100); // 我们再开头插入一个元素100 vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
二 选择一个位置(迭代器) 选择一个我们要插入的元素的数量 选择一个我们要插入的元素
代码和显示效果图如下
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.insert(v1.begin(), 100 , 5); // 我们头插100个5 // 我们之后再试试5个100 vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
earse
和insert对应 earse也有两种使用方式
一. 删除指定位置的内容(迭代器)
代码和显示效果如下
void test8() { vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.erase(v1.begin()); vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; } }
一. 删除指定位置的内容(迭代器) 删除区间的末尾(左闭右开)
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.erase(v1.begin(), v1.begin()+2); // 左边是闭区间 右边是开区间(不删除) vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
find
find函数可以找到容器中我们要寻找的值 并且返回迭代器
find函数有三个参数 迭代器左区间 迭代器右区间 要查找元素 (左闭右开)
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); // v1.erase(v1.begin(), v1.begin()+2); vector<int>::iterator pos = find(v1.begin(), v1.end(), 3); // 找到3 v1.erase(pos); // 删除3 vector<int>::iterator it = v1.begin(); while (it != v1.end()) { cout << *it << " "; it++; }
注意!!!!!!
这里的find函数的头文件是 algorithm !!!
一定要记住! 不是容器的默认函数
swap
通过swap我们可以交换两个容器的值
元素遍历
我们这里遍历有三种方式
迭代器遍历范围for或者方括号遍历
我们这里展示下范围for(其实就是迭代器)
还有方括号遍历
代码和效果图如下
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int>::iterator it = v1.begin(); for (auto& x : v1) { cout << x << " "; } cout << endl; for (size_t i = 0; i < v1.size(); i++) { cout << v1[i] << " "; }
迭代器失效相关问题
实例一
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int>::iterator it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2 v1.erase(v1.begin()); //删除头元素 v1.erase(it); //删除元素2
实例二
void test10() { vector<int> v; for (size_t i = 1; i <= 6; i++) { v.push_back(i); } vector<int>::iterator it = v.begin(); while (it != v.end()) { if (*it % 2 == 0) //删除容器当中的全部偶数 { v.erase(it); } it++; } }
这两个错误都是由于迭代器失效引发的
不难发现 我们在使用迭代器之前都对整个容器进行了增删改操作
这种情况就是导致迭代器失效的直接原因
解决方法也很简单 使用迭代器之前重新赋值一下就好了
解决代码和效果如下
实例一
对于实例一来说我们只需要再找一次我们要删除位置的迭代器就好了
vector<int> v1; // 创造一个空容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int>::iterator it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2 v1.erase(v1.begin()); //删除头元素 it = find(v1.begin(), v1.end(), 2); // 意思是我们要删除2 v1.erase(it); //删除元素2 vector<int>::iterator it1 = v1.begin(); while (it1 != v1.end()) { cout << *it1 << " "; it1++; }
实例二
对于实例二也是一样的
我们只需要在增删改之后重新赋值迭代器就好了
vector<int> v; for (size_t i = 1; i <= 6; i++) { v.push_back(i); } vector<int>::iterator it = v.begin(); while (it != v.end()) { if (*it % 2 == 0) //删除容器当中的全部偶数 { it = v.erase(it); } else { it++; } } vector<int>::iterator it1 = v.begin(); while (it1 != v.end()) { cout << *it1 << " "; it1++; }
总结
本文主要讲解了vector的介绍和使用
由于作者水平有限 错误在所难免 希望大佬看到之后可以及时指正
如果这篇文章帮助到了你 别忘记一键三连啊
阿尼亚 哇酷哇酷!