文章目录
- 一、序列式容器
- 1.vector
- 2.array
- 3.deque
- 4.list
- 5.forward_list
- 二、关联式容器
- 1.set、multiset、unordered_set和unordered_multiset
- 2.map、multimap、unordered_map和unordered_multimap
STL中的容器将一些应用最为广泛的数据结构实现了出来,它主要分为序列式容器和关联式容器两类。
一、序列式容器
1.vector
https://zh.cppreference.com/w/cpp/container/vector
vector是应用最为广泛的顺序容器,可以简单地将它看作是一个能够存放任意类型元素的动态数组,是使用new创建动态数组的替代品。实际上,vector类确实使用new和delete来管理内存,只不过这种工作是自动完成的。vector在尾部添加或移除元素非常快速,但是在中间及起始位置插入元素时可能会导致很多后续元素的重新构造,效率比较低。
向vector中插入元素时,如果已分配的空间不足,不会在后面直接追加分配,而是重新分配所有的空间(默认分配二倍大小的空间),然后依次拷贝原vector中的数据,因此可以通过reserve()
为vector提前预留空间以减少拷贝次数。
此外,也可以通过emplace_back()
原地构造,以避免每次插入时创建临时对象。
#include <iostream>
#include <vector>
using namespace std;
class Car {
private:
int m_id;
public:
explicit Car(int id) : m_id(id) {
cout << "Car(" << id << ")" << endl;
}
Car(const Car &other) {
cout << "copy Car(" << other.m_id << ")" << endl;
this->m_id = other.m_id;
}
~Car() {
cout << "~Car(" << m_id << ")" << endl;
}
};
int main(int argc, char *argv[]) {
vector<Car> v;
// cout << v.capacity() << endl;
// v.reserve(10);
// cout << v.capacity() << endl;
// v.emplace_back(1);
v.push_back(Car(1));
cout << "---" << endl;
// v.emplace_back(2);
v.push_back(Car(2));
cout << "---" << endl;
return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
Car(1) // 构造临时对象
copy Car(1) // 从临时对象向vector中拷贝(使用emplace_back时不会有此过程)
~Car(1) // 析构临时对象(使用emplace_back时不会有此过程)
---
Car(2) // 构造临时对象
copy Car(2) // 从临时对象向vector中拷贝(使用emplace_back时不会有此过程)
copy Car(1) // 从原vector向新vector拷贝 (提前使用reserve时不会有此过程)
~Car(1) // 析构原vector中的对象 (提前使用reserve时不会有此过程)
~Car(2) // 析构临时对象(使用emplace_back时不会有此过程)
---
~Car(2) // 析构新vector中的对象
~Car(1) // 析构新vector中的对象
atreus@MacBook-Pro %
2.array
https://zh.cppreference.com/w/cpp/container/array
vector类的功能比数组强大,但付出的代价是效率稍低。在需要长度固定的数组时,使用普通数组是更好的选择,但代价是不那么方便和安全。因此C++11新增了模板类array,它也位于名称空间std中。和普通数组一样,array对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与普通数组基本相同,但更方便,更安全。
3.deque
https://zh.cppreference.com/w/cpp/container/deque
deque模板类表示双端队列,其实现类似于vector容器,支持随机访问,区别在于从deque对象的起始位置进行插入和删除的时间是固定的,所以如果多数操作发生在序列的起始和结尾处,可以考虑deque。
4.list
https://zh.cppreference.com/w/cpp/container/list
list模板类表示双向链表,除了第一个和最后一个元素外,所有元素都与前后的元素相连接,这意味着可以双向遍历链表。list和vector的关键区别在于,list在链表中任一位置进行插入和删除的时间都是固定的,但很显然list不支持随机访问。
5.forward_list
https://zh.cppreference.com/w/cpp/container/forward_list
C++11新增了容器类forward_list,它实现了单链表,即每个节点都只链接到下一个节点,相比于list,forward_list更简单但功能更紧凑,但功能也更少。
二、关联式容器
1.set、multiset、unordered_set和unordered_multiset
https://zh.cppreference.com/w/cpp/container/set
set表示关联集合,可反转可排序,且键是唯一的,所以不能存储多个相同的值。
集合 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
---|---|---|---|---|---|---|
std::set | 红黑树 | key有序 | key不可重复 | key不可修改 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) |
std::multiset | 红黑树 | key有序 | key可重复 | key不可修改 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) |
std::unordered_set | 哈希表 | key无序 | key不可重复 | key不可修改 | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) |
std::unordered_multiset | 哈希表 | key无序 | key可重复 | key不可修改 | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) |
#include <iostream>
#include <set>
using namespace std;
int main(int argc, char *argv[]) {
set<int> A{1, 2, 3};
set<int> B{2, 3, 4};
set<int> C{5};
set<int> D{1};
set_union(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<int>>(C, C.end()));
set_intersection(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<int>>(D, D.end()));
for (auto i: C) { cout << i << " "; } // 1 2 3 4 5
cout << "\n---\n";
for (auto i: D) { cout << i << " "; } // 1 2 3
return 0;
}
2.map、multimap、unordered_map和unordered_multimap
https://zh.cppreference.com/w/cpp/container/map
map是有序键值对容器,它里面的所有元素都是pair,同时拥有实值(value)和键值(key),且pair的第一元素被视为键值,第二元素被视为实值。map不允许两个元素拥有相同的键值,但multimap允许键值重复。
映射 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
---|---|---|---|---|---|---|
std::map | 红黑树 | key有序 | key不可重复 | key不可修改 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) |
std::multimap | 红黑树 | key有序 | key可重复 | key不可修改 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) |
std::unordered_map | 哈希表 | key无序 | key不可重复 | key不可修改 | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) |
std::unordered_multimap | 哈希表 | key无序 | key可重复 | key不可修改 | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) |