C++:vector容器
一、vector
1.1 vector是什么
vector是C++标准库提供的一个容器类,可以理解为可变长度数组。在初始定义时无需申明长度,可以一直往后填充数据。填充时,vector容器会自动拓宽可用空间。
储存该容器类的头文件是\
vector储存的数据是连续的,和数组一样
一般地,vector拓宽空间时会将已有空间翻倍。
假如vector所处地址没有这么大的连续内存可供使用,编译器会进行内容重分配:寻找一处可存放翻倍后的vector数组的连续空间,将vector数组拷贝过去,时间复杂度是$O(n)$
也因此,有时候使用vector的速度会比使用普通数组慢一点
1.2 vector提供的一些方法
让我们先来看一个具体的vector使用示例:
1 |
|
输出结果是
1 | 12 33 4 88 |
我们对上述涉及的方法逐一介绍
1.3 vector的初始化
vector的定义通过vector<类型名> 数组名 实现,可以不初始化,也可以初始化,还可以在初始化的时候提供初次内存空间
下面我们来看看几种不同的初始化方式
1 | vector<int>a1={1,2,3};//普通初始化 |
补充:只有定义该对象的时候才可以用大括号赋值。
特此申明,以下声明方式会产生偏差
1 | vector<int>a5[10] |
1.4 push_back()和pop_back()
vector的使用类似于栈,只能把数据放入尾部以及从尾部清除。
虽然从编译器提示可以看出$push_back()$括号内是引用变量,但只仅是减少空间复杂度的方法,并不是指向这个变量,而是复制一份放到$vector$容器类内部。
需要注意的是,这里的v.push_back和v.pop_back都是无返回值的方法
1.5 范围 for 循环(Range-based for loop)
1 | for(auto i:a) |
这是一个范围for循环,$auto$ $i$是在表达式内定义的变量,用来接受容器内的数据($auto$是一种占位符,根据 $i$ 的右值自动决定类型)
这个循环会遍历整个容器。
那么,编译器怎么知道vector的范围呢?
1.6 begin()和end()
这里就用到了两个方法:a.begin()和a.end()
它们的返回值是迭代器的值。
迭代器是专门用来遍历容器的指针,可以用于各种容器。
a.begin()返回一个指向容器首位的迭代器值,也就是说它返回的是
$std::vector
通过对迭代器解引用就可以得到容器首位的值
需要注意的是a.end()返回的是指向容器末位的下一位的迭代器值,也就是说是访问不到的值
范围for循环等价于如下代码
1 | for (auto it = a.begin(); it < a.end(); ++it) { |
1.61
除了正向遍历之外,C++还提供了负向遍历的迭代器
$a.rbegin()$,指向末尾元素的迭代器,$a.rend()$,指向首位元素前一位的迭代器。
需要注意的是,假如需要加上只读属性,可以用以下方法:
$a.cbegin()$
$a.crbegin()$
1.7 size()
$a.size()$返回容器a中储存元素的个数
假如是二维容器(顺便在此引入二维容器的定义)
1 | vector<vector<int>> a(10,vector<int>(5,0)); |
那么,调用size()就会返回当前维度元素的个数
二、 array容器类
$array$类容器与$vector$容器很类似,相同的方面就不多做赘述,只表明它们不同的方面。
储存该容器类的头文件是\
2.1 array容器类的声明
因为array类是一个大小固定的类,所以必须在声明时就表明大小,其他方面与vector同
1 | array<int,3> arr; |
总结
以上介绍了$vector$变长数组容器和范围$for$循环的基本内容