STL之Vector
Vector是一个动态数组,它的长度可以随着其所包含的元素的数量而改变,不需要在创建时定义长度。vector内的元素之间总是存在一定的顺序的,是一种有序集合,支持随机访问,所以vector具有常量级的读取效率。但是在对vector进行元素的增删操作时,除非是在vector的末端进行操作,其它时候vector的增删操作效率极低,因为需要对vector内的元素进行移动。
vector的容量和大小
vector在初始创建时会分配出“较其容纳元素”更多的内存,以此来获得优异的效率。这个在初始创建时所分配的内存大小即为vector的容量,可以使用capacity()函数来获取vector的容量大小。当vector内要存储的元素数量超过这个容量大小时,vector就需要重新进行内存分配,以此来获取更大的容量来存储元素。
vector的容量之所以重要的原因有以下两个:
- 一旦vector的内存进行重新分配,vector内元素相关的所有引用、指针和迭代器都会失效。
- 重新分配内存很耗时间,需要将元素逐个复制到新分配的内存中去。
可以使用reserve()函数来保留适当的容量,以此来避免内存的重新分配。另一种避免内存重新分配的方法是在初始化的时候给构造函数传递额外的实参,以此来构建足够的空间,使用这种方法的前提是vector内存储的元素类型提供默认构造函数,对于基础类型都会使用0来进行初始化。但是如果存储的类型很复杂,调用默认构造函数进行初始化也很耗时。如果只是为了保留足够的内存,不如使用reserve()函数。
vector<int> v;
v.reserve(80); //保留容量至80个元素的大小
vector<int> vi(10); //初始化为容量为10个元素的vector
在vector中,不能使用reserve()来缩减容量,当reserve函数中提供的实参小于vector当前的容量时,不会引发任何效果。因为vector的容量不会减小,所以在对vector进行删除操作时,vector中的引用、指针和迭代器不会失效,而在插入元素时,引用、指针和迭代器可能会失效(插入操作可能会引起内存重新分配)。
当两个vector交换内容后,它们的容量也会互换,这个操作会引起vector容量的缩减。
vector的操作
下表列出了vector的非更易型操作。
| 操作 | 效果 |
|---|---|
| c.empty() | 返回是否容器为空(相当于size()==0但也许较快) |
| c.size() | 返回当前的元素个数 |
| c.max_size() | 返回元素个数的最大可能量 |
| c.capacity() | 返回“不进行空间重新分配”条件下的元素最大容量 |
| c.reserve(num) | 如果容量不足就扩大(如果提供的num实参小于当前容量则不没有任何效果) |
| c.shrink_to_fit() | 要求降低容量以符合元素个数(C++11起支持) |
| c1 == c2 | 返回c1是否等于c2(对容器中的每个元素调用==) |
| c1 != c2 | 返回c1是否不等于c2 |
| c1 < c2 | 返回c1是否小于c2 |
| c1 > c2 | 返回c1是否大于c2 |
| c1 <= c2 | 返回c1是否不小于c2 |
| c1 >= c2 | 返回c1是否大于等于c2 |
下表列出了vector的插入和删除操作函数,在插入和删除操作中,必须保证:
- 迭代器必须指向一个合法的位置;
- 区间的起始位置不能在结束位置之后
| 操作 | 效果 |
|---|---|
| c.push_back(elem) | 在末尾处添加一个元素 |
| c.pop_back() | 移除最后一个元素,但不返回它 |
| c.insert(pos, elem) | 在pos之前插入一个元素,并返回新元素的位置 |
| c.insert(pos, n , elem) | 在pos之前插入n个元素,并返回第一个新元素的位置 |
| c.insert(pos, beg, end) | 在pos之前插入区间[beg, end)内的所有元素,并返回第一个新元素的位置 |
| c.insert(pos, initlist) | 在pos之前插入初始值列内的所有元素,并返回第一个新元素的位置 |
| c.emplace(pos, args...) | 在pos之前插入以args为初值的元素,并返回第一个新元素的位置 |
| c.emplace_back(args...) | 在末尾插入以args为初值的元素,不返回任何值 |
| c.erase(pos) | 删除pos位置上的元素,并返回下一个元素的位置 |
| c.erase(beg, end) | 删除[beg, end)区间内的元素,并返回下一个元素的位置 |
| c.resize(num) | 将元素数量改为num(若size()变大,则多出来的元素全部以默认构造函数完成初始化) |
| c.resize(num, elem) | 将元素数量改为num,如果size()变大,则多出来的元素全都是elem的拷贝 |
| c.clear() | 清空所有元素 |
vector<bool>
C++标准库针对元素类型为bool的vector专门设计了一个特殊化的版本,目的是优化其空间使用量。一般实现版本中会为vector中的每个bool元素分配到少1byte的空间,而vector<bool>特化版内部只使用1bit来存放一个元素。这么处理虽然节省了存储空间,但是C++的最小可定值是以byte为单位的,因此在特化版中的引用和迭代器需要做特殊处理。因此,vector<bool>的迭代器并不是一个真正的随机访问迭代器。此外,vector<bool>的速度可能会比一般的vector要慢一些,因为它的所有操作都需要转换为位来进行操作。
vector<bool>的特殊操作如下表所示:
| 操作 | 效果 |
|---|---|
| c.flip() | 将所有bool元素值取反,亦即对所有位求补数 |
| c[idx].flip() | 将索引为idx的位元素反相 |
| c[idx] = val | 将索引为idx的位元素赋值为val |
| c[idx1] = c[idx2] | 将索引为idx的位元素赋值为索引为idx2的位元素的值 |