大纲
顺序容器
vector
容器介绍
vector 底层所采用的数据结构是线性连续空间(单向开口的连续内存空间),可以理解为支持动态开辟内存空间的数组。vector 往尾部添加或移除元素的效率非常高,但是往头部或者中部插入元素或移除元素则比较耗时。特别注意,vector 一旦需要执行扩容操作,那么每次都会以原来空间大小的 2 倍进行扩容。
![]()
声明
插入
vec.push_back(20)
,往容器尾部插入元素,会导致容器扩容vec.insert(iterator, 30)
,往迭代器指向的位置插入元素,会导致容器扩容
删除
vec.pop_back()
,删除容器尾部的元素vec.erase(iterator)
,删除迭代器指向的元素
查询
vec[5]
,基于下标的随机访问iterator
,迭代器遍历for_each
,循环遍历find
,查找元素
其他
vec.size()
,获取容器中元素数量vec.empty()
,判断容器是否为空vec.swap(vec2)
,交换两个容器的元素vec.reserve(size)
,预留容器空间,只会给容器的底层开辟指定大小的内存空间,并不会添加新的元素,主要用于减少频繁扩容的次数vec.resize(size)
,重新指定容器的大小,不仅会给容器的底层开辟指定大小的内存空间,还会以默认值填充新的位置vec.resize(size, item)
,重新指定容器的大小,不仅会给容器的底层开辟指定大小的内存空间,还会以指定值填充新的位置
特别注意
对 vector 容器进行连续的插入(insert
)或者删除(erase
)操作时,一定要更新迭代器;否则第一次插入或删除操作完成后,迭代器就会失效。
案例代码一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <iostream> #include <vector>
using namespace std;
int main() { srand(time(nullptr));
vector<int> vec;
for (int i = 0; i < 10; i++) { vec.push_back(rand() % 100 + 1); }
cout << "size: " << vec.size() << endl;
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { cout << *it << " "; } cout << endl;
cout << "vec[3] = " << vec[3] << endl;
cout << "================================" << endl;
for (vector<int>::iterator it = vec.begin(); it != vec.end();) { if (*it % 2 == 0) { it = vec.erase(it); } else { ++it; } }
for (int i = 0; i < vec.size(); i++) { cout << vec[i] << " "; } cout << endl;
cout << "================================" << endl;
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { if (*it % 2 != 0) { it = vec.insert(it, *it - 1); ++it; } }
for (int i = 0; i < vec.size(); i++) { cout << vec[i] << " "; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6 7
| size: 10 94 80 7 45 20 57 74 73 16 19 vec[3] = 45 ================================ 7 45 57 73 19 ================================ 6 7 44 45 56 57 72 73 18 19
|
案例代码二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <iostream> #include <vector>
using namespace std;
int main() { srand(time(nullptr));
vector<int> vec; cout << "size: " << vec.size() << endl; cout << "empty: " << (vec.empty() ? "true" : "false") << endl;
vec.reserve(10); cout << "size: " << vec.size() << endl; cout << "empty: " << (vec.empty() ? "true" : "false") << endl;
for (int i = 0; i < 10; i++) { vec.push_back(rand() % 100 + 1); } cout << "size: " << vec.size() << endl; cout << "empty: " << (vec.empty() ? "true" : "false") << endl;
cout << "================================" << endl;
vector<int> vec2; cout << "size: " << vec2.size() << endl; cout << "empty: " << (vec2.empty() ? "true" : "false") << endl;
vec2.resize(10); cout << "size: " << vec2.size() << endl; cout << "empty: " << (vec2.empty() ? "true" : "false") << endl;
for (int i = 0; i < 10; i++) { vec2.push_back(rand() % 100 + 1); } cout << "size: " << vec2.size() << endl; cout << "empty: " << (vec2.empty() ? "true" : "false") << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| size: 0 empty: true size: 0 empty: true size: 10 empty: false ================================ size: 0 empty: true size: 10 empty: false size: 20 empty: false
|
deque
容器介绍
deque 一种双向开口的连续线性空间(双端队列容器),底层的数据结构是支持动态开辟内存空间的二维数组。所谓双向开口,意思是可以在头尾两端分别进行元素的插入和移除操作。虽然 vector 也可以在头尾两端进行操作,但是其头部操作的效率非常低,无法被接受。deque 和 vector 的最大差异,一在于 deque 允许于常数项时间内对头端进行元素的插入或移除操作,二在于 deque 没有所谓容量 capacity
的观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。换句话说,像 vector 那样因旧空间不足而重新配置一块更大的空间,然后拷贝元素,再释放旧空间这样的事情不会发生在 deque 身上,也因此 deque 没有必要提供所谓的空间保留(reserve)功能。虽然 deque 也提供了随机迭代器(Random Access Iterator),但是它的迭代器并不是普通的指针,其复杂度和 vector 不是一个量级,这会影响各个层面的运算效率。因此,除非有必要,应该尽可能的使用 vector,而不是 deque。对 deque 进行的排序操作,为了提高效率,可将 deque 先完整的复制到一个 vector 中,然后对 vector 容器进行排序,再复制回 deque。
![]()
deque 本质上是由一段一段的定量连续空间(分段连续内存空间)构造而成,一旦有必要在 deque 的头端或尾端增加新空间,便会配置一段新的定量连续空间,然后串接在整个 deque 的头端或尾端。deque 最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口;这避开了重新配置空间、复制数据、释放空间的轮回,代价就是复杂的迭代器架构。既然 deque 使用的是分段连续内存空间,那么就必须有中央控制器,维持其整体连续的假象,这样也导致了数据结构的设计及迭代器的前进后退操作颇为繁琐,deque 底层实现的代码远比 vector 或 list 都多得多。
![]()
deque 内部的中控器维护的是每个缓冲区的地址,而缓冲区则存放着真实的数据,目的是让 deque 使用起来像是一片连续的内存空间。deque 采取一块所谓的 map
(注意,不是 STL 的 map 容器)作为主控,这里所谓的 map
是一小块连续的内存空间,其中每一个元素(节点)都是一个指针,指向另一段连续性内存空间,称作缓冲区,缓冲区才是 deque 的存储空间的主体。
声明
插入
deq.push_back(20)
,往尾部插入元素deq.push_front(20)
,往头部插入元素deq.insert(iterator, 20)
,往迭代器指向的位置插入元素
删除
deq.pop_back()
,往尾部删除元素deq.pop_front()
,往头部删除元素deq.erase(it)
,删除迭代器指向的元素
查询
deque 与 vector 的区别
- deque 对头部的元素插入与删除,其速度比 vector 快。
- deque 对中间的元素插入与删除,其速度比 vector 慢。
- vector 对于头部的插入与删除效率极低,数据量越大,效率越低。
- vector 访问元素的速度会比 deque 快,这和两者的内部实现有关。
案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| #include <iostream> #include <deque>
using namespace std;
void printDeque(const deque<int> &d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; }
int main() { cout << "------ deque 大小操作 ------" << endl;
deque<int> d1; d1.assign(5, 10); printDeque(d1);
bool empty = d1.empty(); cout << (empty ? "yes" : "no") << endl;
size_t size = d1.size(); cout << size << endl;
d1.resize(7); printDeque(d1);
d1.resize(10, 8); printDeque(d1);
cout << "------ deque 读取操作 ------" << endl;
deque<int> d2; d2.push_back(1); d2.push_back(2); d2.push_back(3); d2.push_back(4); d2.push_back(5);
int num1 = d2.at(2); cout << "num1 = " << num1 << endl;
int num2 = d2[3]; cout << "num2 = " << num2 << endl;
int font = d2.front(); cout << "font = " << font << endl;
int back = d2.back(); cout << "back = " << back << endl;
cout << "------ deque 插入操作 ------" << endl;
deque<int> d3(3, 8); printDeque(d3);
d3.insert(d3.begin(), 10); printDeque(d3);
d3.insert(d3.begin(), 2, 11); printDeque(d3);
deque<int> d4(2, 12); d3.insert(d3.begin(), d4.begin(), d4.end()); printDeque(d3);
d4.push_front(13); printDeque(d4);
d4.push_back(11); printDeque(d4);
cout << "------ deque 删除操作 ------" << endl;
deque<int> d5; d5.push_back(1); d5.push_back(2); d5.push_back(3); d5.push_back(4); d5.push_back(5); d5.push_back(6);
d5.erase(d5.begin()); printDeque(d5);
d5.pop_front(); printDeque(d5);
d5.pop_back(); printDeque(d5);
d5.clear();
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ------ deque 大小操作 ------ 10 10 10 10 10 no 5 10 10 10 10 10 0 0 10 10 10 10 10 0 0 8 8 8 ------ deque 读取操作 ------ num1 = 3 num2 = 4 font = 1 back = 5 ------ deque 插入操作 ------ 8 8 8 10 8 8 8 11 11 10 8 8 8 12 12 11 11 10 8 8 8 13 12 12 13 12 12 11 ------ deque 删除操作 ------ 2 3 4 5 6 3 4 5 6 3 4 5
|
list
容器介绍
list 是一个双向链表容器,而且还是一个双向循环链表,可以高效地进行插入和删除元素。链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的(如下图所示)。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相较于 vector 的连续线性空间,list 就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list 对于空间的运用有绝对的精准,一点也不浪费。值得一提的是,对于任何位置的元素插入或元素的移除,list 永远是常数时间的耗时(效率较高);但对于查询操作来说,list 的执行效率较低。
![]()
声明
插入
mylist.push_back(20)
,往尾部插入元素mylist.push_front(20)
,往头部插入元素mylist.insert(iterator, 20)
,往迭代器指向的位置插入元素
删除
mylist.pop_back()
,往尾部删除元素mylist.pop_front()
,往头部删除元素mylist.erase(it)
,删除迭代器指向的元素
查询
链表的特性
- 链表采用动态内存分配,不会造成内存浪费和溢出。
- 链表虽然灵活,但是空间和时间的额外耗费较大。
- 链表执行插入和删除操作都十分方便,仅修改指针即可实现,不需要移动大量元素。
- 链表的访问效率比数组要低,适合需要频繁插入、删除元素的场景(读少写多)。
- 链表不可以随机存取元素,所以不支持
at.(pos)
函数与 []
操作符的使用。
案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| #include <iostream> #include <list>
using namespace std;
void printList(list<int> &L) { for (list<int>::iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; }
void reversePrintList(list<int> &L) { for (list<int>::reverse_iterator it = L.rbegin(); it != L.rend(); it++) { cout << *it << " "; } cout << endl; }
int main() { cout << "------ list 插入操作 ------" << endl;
list<int> myList1;
myList1.push_back(10); myList1.push_back(20); myList1.push_back(30); printList(myList1);
myList1.push_front(300); myList1.push_front(200); myList1.push_front(100); printList(myList1);
myList1.insert(myList1.begin(), 400); printList(myList1);
myList1.insert(myList1.begin(), 2, 500); printList(myList1);
list<int> myList2; myList2.push_back(1); myList2.push_back(2); myList2.push_back(3); myList1.insert(myList1.begin(), myList2.begin(), myList2.end()); printList(myList1);
cout << "------ list 删除操作 ------" << endl;
myList1.pop_front(); printList(myList1);
myList1.pop_back(); printList(myList1);
myList1.erase(myList1.begin()); printList(myList1);
myList1.remove(100); printList(myList1);
cout << "------ list 读取操作 ------" << endl;
cout << myList1.front() << endl;
cout << myList1.back() << endl;
cout << "------ list 清空操作 ------" << endl;
list<int> myList3; myList3.push_back(10); myList3.push_back(10); myList3.clear(); printList(myList3);
cout << "------ list 大小操作 ------" << endl;
cout << "size = " << myList1.size() << endl;
bool isEmpty = myList1.empty(); cout << "isEmpty = " << (isEmpty ? "true" : "false") << endl;
myList1.resize(6); cout << "size = " << myList1.size() << endl;
myList1.resize(9, 11); printList(myList1); cout << "size = " << myList1.size() << endl;
cout << "------ list 逆向遍历操作 ------" << endl;
list<int> myList11; myList11.push_back(1); myList11.push_back(2); myList11.push_back(3); reversePrintList(myList11);
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ------ list 插入操作 ------ 10 20 30 100 200 300 10 20 30 400 100 200 300 10 20 30 500 500 400 100 200 300 10 20 30 1 2 3 500 500 400 100 200 300 10 20 30 ------ list 删除操作 ------ 2 3 500 500 400 100 200 300 10 20 30 2 3 500 500 400 100 200 300 10 20 3 500 500 400 100 200 300 10 20 3 500 500 400 200 300 10 20 ------ list 读取操作 ------ 3 20 ------ list 清空操作 ------
------ list 大小操作 ------ size = 8 isEmpty = false size = 6 3 500 500 400 200 300 11 11 11 size = 9 ------ list 逆向遍历操作 ------ 3 2 1
|
关联容器
无序关联容器
在 C++ 中,无序关联容器的底层数据结构都是链式哈希表(也称为哈希链表),常用的无序关联容器有:
unordered_set
: 一个无序容器,存储唯一键值(不允许重复),基于链式哈希表实现,提供快速的插入、删除和查找操作。unordered_multiset
: 一个无序容器,存储键值(允许重复),基于链式哈希表实现,提供快速的多键插入、删除和查找操作。unordered_map
: 一个无序的键值对容器(键不允许重复),基于链式哈希表实现,键唯一且与对应的值关联,提供高效的键查找。unordered_multimap
: 一个无序的键值对容器(键允许重复),基于链式哈希表实现,允许多个键相同的键值对,提供快速的键查找和多值存储。
在 C++ 中,无序关联容器有以下的常用操作:
插入
删除
erase(val)
,删除元素erase(iterator)
,删除迭代器指向的元素
查询
iterator
:迭代器遍历for_each
,循环遍历for
:循环遍历find
:查找元素
其他
size()
:获取容器中元素数量count(val)
:统计容器中某个元素的数量
unordered_set
案例代码
本节将演示 unordered_set
容器的简单使用。值得一提的是,unordered_multiset
容器的使用跟 unordered_set
容器类似,这里不再累述。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <unordered_set>
using namespace std;
int main() { srand(time(nullptr));
unordered_set<int> set1;
for (int i = 0; i < 50; i++) { set1.insert(rand() % 20 + 1); }
for (auto it = set1.begin(); it != set1.end(); ++it) { cout << *it << " "; } cout << endl;
cout << set1.size() << endl;
cout << set1.count(5) << endl;
set1.erase(20);
auto iterator = set1.find(15); if (iterator != set1.end()) { cout << "find item : " << *iterator << endl; } else { cout << "not find item" << endl; }
for (int i: set1) { cout << i << " "; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5
| 16 8 12 18 20 15 13 9 2 7 19 1 10 6 17 3 14 4 5 19 1 find item : 15 16 8 12 18 15 13 9 2 7 19 1 10 6 17 3 14 4 5
|
unordered_map
案例代码
本节将演示 unordered_map
容器的简单使用。值得一提的是,unordered_multimap
容器的使用跟 unordered_map
容器类似,这里不再累述。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <string> #include <unordered_map>
using namespace std;
int main() { srand(time(nullptr));
unordered_map<int, string> map1;
map1.insert(make_pair(1001, "Tom")); map1.insert(make_pair(1002, "Peter")); map1.insert(make_pair(1003, "David"));
cout << map1[1002] << endl;
map1[1004] = "Jim";
cout << map1.size() << endl;
map1.erase(1003);
auto iterator = map1.find(1001); if (iterator != map1.end()) { cout << "finded, key: " << iterator->first << ", value: " << iterator->second << endl; } else { cout << "not finded" << endl; }
for (auto it = map1.begin(); it != map1.end(); ++it) { cout << "key: " << it->first << ", value: " << it->second << endl; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6
| Peter 4 finded, key: 1001, value: Tom key: 1004, value: Jim key: 1002, value: Peter key: 1001, value: Tom
|
有序关联容器
在 C++ 中,有序关联容器的底层数据结构都是红黑树(一种平衡二叉搜索树),常用的有序关联容器有:
set
: 一个有序容器,存储唯一键值(不允许重复),基于红黑树实现,提供高效的元素插入、删除和有序遍历。multiset
: 一个有序容器,存储键值(允许重复),基于红黑树实现,支持多键插入和有序遍历。map
: 一个有序的键值对容器(键不允许重复),基于红黑树实现,键唯一且与对应的值关联,支持高效查找和有序遍历。multimap
: 一个有序的键值对容器(键允许重复),基于红黑树实现,允许键重复,支持多键查找和有序存储。
set
本节将演示 set
容器的简单使用。值得一提的是,multiset
容器的使用跟 set
容器类似,这里不再累述。
案例代码一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <set>
using namespace std;
int main() { srand(time(nullptr));
set<int> set1;
for (int i = 0; i < 20; i++) { set1.insert(rand() % 100 + 1); }
for (auto it = set1.begin(); it != set1.end(); ++it) { cout << *it << " "; } cout << endl;
cout << set1.size() << endl;
cout << set1.count(5) << endl;
set1.erase(20);
auto iterator = set1.find(15); if (iterator != set1.end()) { cout << "find item : " << *iterator << endl; } else { cout << "not find item" << endl; }
for (int i: set1) { cout << i << " "; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5
| 5 21 22 26 27 36 39 41 51 55 60 67 81 89 90 91 94 96 18 1 not find item 5 21 22 26 27 36 39 41 51 55 60 67 81 89 90 91 94 96
|
案例代码二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <set> #include <string>
using namespace std;
class Student {
public: Student(long id, string name) : _id(id), _name(name) {
}
bool operator<(const Student &other) const { return this->_id < other._id; }
friend ostream &operator<<(ostream &out, const Student &student);
private : long _id; string _name;
};
ostream &operator<<(ostream &out, const Student &student) { cout << "id: " << student._id << ", name: " << student._name; return out; }
int main() { set<Student> set1;
set1.insert(Student(1001, "Tom")); set1.insert(Student(1002, "Jim")); set1.insert(Student(1003, "Peter"));
for (auto it = set1.begin(); it != set1.end(); ++it) { cout << *it << endl; }
return 0; }
|
程序运行输出的结果如下:
1 2 3
| id: 1001, name: Tom id: 1002, name: Jim id: 1003, name: Peter
|
map
本节将演示 map
容器的简单使用。值得一提的是,multimap
容器的使用跟 map
容器类似,这里不再累述。
案例代码一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <string> #include <map>
using namespace std;
int main() { srand(time(nullptr));
map<int, string> map1;
map1.insert(make_pair(1001, "Tom")); map1.insert(make_pair(1002, "Peter")); map1.insert(make_pair(1003, "David"));
cout << map1[1002] << endl;
map1[1004] = "Jim";
cout << map1.size() << endl;
map1.erase(1003);
auto iterator = map1.find(1001); if (iterator != map1.end()) { cout << "finded, key: " << iterator->first << ", value: " << iterator->second << endl; } else { cout << "not finded" << endl; }
for (auto it = map1.begin(); it != map1.end(); ++it) { cout << "key: " << it->first << ", value: " << it->second << endl; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6
| Peter 4 finded, key: 1001, value: Tom key: 1001, value: Tom key: 1002, value: Peter key: 1004, value: Jim
|
案例代码二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <iostream> #include <string> #include <map>
using namespace std;
class Student {
public:
Student() { this->_id = 0; this->_name = ""; }
Student(long id, string name) : _id(id), _name(name) {
}
friend ostream &operator<<(ostream &out, const Student &student);
private : long _id; string _name;
};
ostream &operator<<(ostream &out, const Student &student) { cout << "id: " << student._id << ", name: " << student._name; return out; }
int main() { map<int, Student> map1;
map1.insert({1001, Student(1001, "Jim")}); map1.insert({1002, Student(1002, "Peter")}); map1.insert({1003, Student(1003, "David")});
cout << map1[1002] << endl;
for (auto it = map1.begin(); it != map1.end(); ++it) { cout << "key: " << it->first << ", value: " << it->second << endl; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4
| id: 1002, name: Peter key: 1001, value: id: 1001, name: Jim key: 1002, value: id: 1002, name: Peter key: 1003, value: id: 1003, name: David
|
容器适配器
在 C++ 中,常用的容器适配器有:
stack
: 一个遵循后进先出(LIFO)原则的容器适配器,底层默认是基于 deque
实现,也可以使用 vector
或 list
替代底层容器,支持在栈顶插入、删除和访问元素的操作。queue
: 一个遵循先进先出(FIFO)原则的容器适配器,底层默认是基于 deque
实现,支持在队尾插入元素和在队头移除、访问元素的操作。priority_queue
: 一个基于堆实现的容器适配器(即优先级队列),底层默认使用 vector
作为容器存储,借助堆算法按优先级(默认大顶堆)访问最高优先级的元素。
容器迭代器的特点
- 容器适配器没有自己的迭代器。
- 容器适配器的底层没有自己的数据机构,它本质是另外一个容器的封装,它的函数全部由底层依赖的容器来实现。
stack
案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream> #include <stack>
using namespace std;
int main() { srand(time(nullptr));
stack<int> s1;
for (int i = 0; i < 20; i++) { int item = rand() % 100 + 1; s1.push(item); cout << item << " "; } cout << endl;
cout << "size: " << s1.size() << endl;
while (!s1.empty()) { cout << s1.top() << " "; s1.pop(); }
return 0; }
|
程序运行输出的结果如下:
1 2 3
| 10 80 23 89 30 85 6 58 5 67 32 98 13 65 42 60 75 85 77 57 size: 20 57 77 85 75 60 42 65 13 98 32 67 5 58 6 85 30 89 23 80 10
|
queue
案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream> #include <queue>
using namespace std;
int main() { srand(time(nullptr));
queue<int> q1;
for (int i = 0; i < 20; i++) { int item = rand() % 100 + 1; q1.push(item); cout << item << " "; } cout << endl;
cout << "size: " << q1.size() << endl;
while (!q1.empty()) { cout << q1.front() << " "; q1.pop(); }
return 0; }
|
程序运行输出的结果如下:
1 2 3
| 14 45 87 90 95 32 66 27 9 92 96 88 93 68 72 55 42 37 35 64 size: 20 14 45 87 90 95 32 66 27 9 92 96 88 93 68 72 55 42 37 35 64
|
priority_queue
案例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream> #include <queue>
using namespace std;
int main() { srand(time(nullptr));
priority_queue<int> pque;
for (int i = 0; i < 20; i++) { int item = rand() % 100 + 1; pque.push(item); cout << item << " "; } cout << endl;
cout << "size: " << pque.size() << endl;
while (!pque.empty()) { cout << pque.top() << " "; pque.pop(); }
return 0; }
|
程序运行输出的结果如下:
1 2 3
| 85 32 2 2 38 96 10 2 83 34 1 64 19 90 64 20 6 81 100 47 size: 20 100 96 90 85 83 81 64 64 47 38 34 32 20 19 10 6 2 2 2 1
|