C++中有多种种类的容器,包括:顺序容器(Sequence Containers)、关联容器(Associative Containers)、无序容器(Unordered Containers)和容器适配器(Container Adapters)。
上一篇文章介绍了顺序容器,这篇文章就来详细一下关联容器。关联容器实现了可以快速搜索的排序数据结构,具有O(log n)的复杂度。它包括set
、map
、multiset
和multimap
。
1 Set
集合(Set
)是一种关联容器类型,它有如下特点:
- 存储顺序:按排序顺序存储元素。
- 值特征:每个元素必须是唯一的
- 值性质:元素的值一旦添加到集合中就不能被修改,尽管可以删除再添加
- 原理:二叉搜索树
- 排列顺序:集合中的值没有索引
下面来看一下Set
的声明方式:
#include <set>
std::set <data_type> set_name;
例:
set<int> val; // defining an empty set
set<int> val = {6, 10, 5, 1}; // defining a set with values
Set
中的元素是唯一的,下面看一个例子:
#include <iostream>
#include <set>
int main()
{
std::set<char> a;
a.insert('G');
a.insert('F');
a.insert('G');
for (auto& str : a) {
std::cout << str << ' '; //F G
}
return 0;
}
设置Set
为降序排列(不指名的话默认为升序):
std::set <data_type, greater<data_type>> set_name;
来看一个例子:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int, greater<int> > s1;
s1.insert(10);
s1.insert(5);
s1.insert(12);
s1.insert(4);
for (auto i : s1) {
cout << i << ' ';
}
return 0;
}
基本方法
begin()
:返回一个迭代器,指向集合中的第一个元素end()
:返回一个迭代器,指向集合中最后一个元素后的理论元素size()
:返回集合中的元素数量max_size()
:返回集合可以容纳的最大元素数量empty()
:返回集合是否为空
#include <iostream>
#include <iterator>
#include <set>
using namespace std;
int main()
{
set<int, greater<int> > s1;
s1.insert(40);
s1.insert(30);
s1.insert(60);
s1.insert(20);
s1.insert(50);
s1.insert(50);
s1.insert(10);
set<int, greater<int> >::iterator itr;
cout << "\nThe set s1 is : \n";
for (itr = s1.begin(); itr != s1.end(); itr++) {
cout << *itr << " "; //60 50 40 30 20 10
}
cout << endl;
set<int> s2(s1.begin(), s1.end());
cout << "\nThe set s2 after assign from s1 is : \n";
for (itr = s2.begin(); itr != s2.end(); itr++) {
cout << *itr << " "; //10 20 30 40 50 60
}
cout << endl;
cout << "\ns2 after removal of elements less than 30 :\n";
s2.erase(s2.begin(), s2.find(30));
for (itr = s2.begin(); itr != s2.end(); itr++) {
cout << *itr << " "; //30 40 50 60
}
int num;
num = s2.erase(50);
cout << "\ns2.erase(50) : " << num << " removed\n"; //1
for (itr = s2.begin(); itr != s2.end(); itr++) {
cout << *itr << " "; //30 40 60
}
cout << endl;
cout << "s1.lower_bound(40) : " << *s1.lower_bound(40) << endl; //40(第一个不小于40的元素)
cout << "s1.upper_bound(40) : " << *s1.upper_bound(40) << endl; //30(第一个不大于40的元素)
cout << "s2.lower_bound(40) : " << *s2.lower_bound(40) << endl; //40
cout << "s2.upper_bound(40) : " << *s2.upper_bound(40) << endl; //60
return 0;
}
其它方法
Function | Description |
---|---|
begin()/end() | 返回指向第一个/最后一个元素的迭代器 |
rbegin()/rend() | 返回指向最后一个元素/集合开始之前位置的反向迭代器 |
crbegin()/crend() | 返回一个指向集合的最后一个/第一个元素的常量反向迭代器 |
cbegin()/cend() | 返回一个指向集合开始/结束的常量随机访问迭代器 |
size() | 返回集合中元素的数量 |
max_size() | 返回集合可以容纳的最大元素数量。 |
empty() | 判断集合是否为空 |
insert() | 在集合中添加一个新元素 |
insert (iterator position, const g) | 在迭代器指向的位置添加一个新元素‘g’ |
erase(iterator position) | 删除迭代器指向的元素 |
erase(const g) | 删除值为‘g’的元素 |
clear() | 删除集合中的所有元素 |
key_comp() / value_comp() | 比较两个元素的大小以确定它们的排列顺序/比较元素大小(不常用) |
find(const g) | 如果找到元素’g’,则返回指向它的迭代器,否则返回指向集合末尾的迭代器。 |
count(const g) | 根据元素’g’是否存在于集合中返回1或0 |
lower_bound(const g) | 返回指向集合中第一个与’g’等价或肯定在’g’之前的元素的迭代器 |
upper_bound(const g) | 返回指向集合中第一个在’g’之后的元素的迭代器。 |
equal_range() | 查找一个键值,并返回一个迭代器分别指向该键值的最小和最大元素(可用此迭代器遍历) |
emplace() | 将新元素插入set容器中,当且仅当插入的元素是不存在于集合中时 |
emplace_hint() | 在已知的位置插入一个值并返回一个迭代器,指向插入位置。如果参数中传递的元素已经存在,则返回一个指向现有元素位置的迭代器。 |
swap() | 交换两个集合的内容,但两个集合的类型必须相同,尽管大小可能不同 |
get_allocator() | 获取与容器关联的分配器对象的副本,以便进行自定义的内存管理 |
2 Map
Map是以映射方式存储元素的关联容器。每个元素都有一个键值和一个映射值。
基本方法
begin()
:返回映射中第一个元素的迭代器end()
:返回一个迭代器,指向映射中最后一个元素后面的理论元素size()
:返回映射中的元素数量max_size()
:返回映射可以容纳的最大元素数量empty()
:返回映射是否为空insert(keyvalue, mapvalue)
:向映射添加新元素erase(iterator position)
:删除迭代器指向的位置处的元素erase(const g)
:从映射中删除键值“g”clear()
:从映射中删除所有元素
例1:begin()
,end()
和size()
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> mp;
mp["one"] = 1;
mp["two"] = 2;
mp["three"] = 3;
map<string, int>::iterator it = mp.begin();
while (it != mp.end()) {
//[one]=1 [three]=3 [two]=2
cout << "[" << it->first << "]=" << it->second << endl;
++it;
}
cout << "Size of map: " << mp.size() << endl; //3
return 0;
}
例2:Map
的使用
#include <iostream>
#include <iterator>
#include <map>
using namespace std;
int main()
{
map<int, int> gquiz1;
gquiz1.insert(pair<int, int>(1, 40));
gquiz1.insert(pair<int, int>(2, 30));
gquiz1.insert(pair<int, int>(3, 60));
gquiz1.insert(pair<int, int>(4, 20));
gquiz1.insert(pair<int, int>(5, 50));
gquiz1.insert(pair<int, int>(6, 50));
gquiz1[7] = 10;// another way of inserting a value in a map
map<int, int>::iterator itr;
cout << "\nThe map gquiz1 is : \n";
for (itr = gquiz1.begin(); itr != gquiz1.end(); ++itr) {
//[1,40][2,30][3,60][4,20][5,50][6,50][7,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
map<int, int> gquiz2(gquiz1.begin(), gquiz1.end());
cout << "\nThe map gquiz2 after" << " assign from gquiz1 is : \n";
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[1,40][2,30][3,60][4,20][5,50][6,50][7,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
cout << "\ngquiz2 after removal of elements less than key=3 : \n";
gquiz2.erase(gquiz2.begin(), gquiz2.find(3));
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[3,60][4,20][5,50][6,50][7,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
int num;
num = gquiz2.erase(4);
cout << "\ngquiz2.erase(4) : " << num << " removed \n";
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[3,60][5,50][6,50][7,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
cout << "gquiz1.lower_bound(5) : " << " KEY = " << gquiz1.lower_bound(5)->first << ' ';
cout << " ELEMENT = " << gquiz1.lower_bound(5)->second << endl;//KEY = 5 ELEMENT = 50
cout << "gquiz1.upper_bound(5) : " << " KEY = " << gquiz1.upper_bound(5)->first << ' ';
cout << " ELEMENT = " << gquiz1.upper_bound(5)->second << endl;//KEY = 6 ELEMENT = 50
return 0;
}
其它方法
Function | Definition |
---|---|
insert() | 在映射容器中插入具有特定键的元素 |
count(g) | 返回与映射中键值“g”匹配的元素的数量 |
equal_range(k) | 查找一个键值,并返回一个迭代器分别指向该键值的最小和最大元素(可用此迭代器遍历) |
erase() | 从容器中删除元素 |
rbegin()/rend() | 返回指向映射中最后一个元素/第一个键值对之前的理论元素的反向迭代器 |
find(g) | 如果找到,返回指向映射中键值“g”的元素的迭代器,否则返回指向末尾的迭代器 |
crbegin()/crend() | 返回指向映射中最后一个元素/第一个键值对之前的理论元素的常量反向迭代器 |
cbegin()/cend() | 返回指向映射容器中第一个元素/最后一个元素之后的理论元素的常量迭代器 |
emplace() | 在映射容器中插入键及其元素 |
max_size() | 返回映射容器可以容纳的最大元素数量 |
upper_bound()/lower_bound() | 返回一个迭代器,指向第一个键值大于/不小于k的元素,若没有则返回end() |
= | 将一个容器的容量分配给另一个容器,替换其当前内容 |
emplace_hint() | 在已知的位置(迭代器)插入一个值并返回一个迭代器,指向插入位置 |
key_comp()/value_comp() | 比较两个元素的大小以确定它们的排列顺序/比较元素大小(不常用) |
size() | 返回映射中元素的数量 |
empty() | 返回映射是否为空 |
begin()/end() | 返回映射中第一个/最后一个元素的迭代器 |
[] | 该操作符用于引用操作符中给定位置的元素 |
clear() | 从映射中删除所有元素 |
at(k) | 返回与键k关联的元素的引用 |
swap() | 交换两个映射的内容,但两个映射必须是同一类型 |
3 Multiset
Multiset
是一种类似于Set
的关联容器,不同之处在于多个元素可以具有相同的值。
基本方法
begin()
:返回Multiset
中第一个元素的迭代器end()
:返回Multiset
中最后一个元素之后的迭代器size()
:返回Multiset
中的元素数max_size()
:返回Multiset
可以容纳的最大元素数empty()
:返回Multiset
是否为空insert(x)
:在Multiset
中插入元素xclear()
:从Multiset
中删除所有元素erase(x)
:删除所有出现的x
实例
#include <iostream>
#include <iterator>
#include <set>
using namespace std;
int main()
{
multiset<int, greater<int> > gquiz1;
gquiz1.insert(40);
gquiz1.insert(30);
gquiz1.insert(60);
gquiz1.insert(20);
gquiz1.insert(50);
gquiz1.insert(50);
gquiz1.insert(10);
multiset<int, greater<int> >::iterator itr;
cout << "\nThe multiset gquiz1 is : \n";
for (itr = gquiz1.begin(); itr != gquiz1.end(); ++itr) {
cout << *itr << " "; //60 50 50 40 30 20 10
}
cout << endl;
multiset<int> gquiz2(gquiz1.begin(), gquiz1.end());
cout << "\nThe multiset gquiz2 \nafter assign from gquiz1 is : \n";
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
cout << *itr << " "; //10 20 30 40 50 50 60
}
cout << endl;
cout << "\ngquiz2 after removal of elements less than 30 : \n";
gquiz2.erase(gquiz2.begin(), gquiz2.find(30));
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
cout << *itr << " "; //30 40 50 50 60
}
int num;
num = gquiz2.erase(50);
cout << "\ngquiz2.erase(50) : " << num << " removed \n"; //2
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
cout << *itr << " "; //30 40 60
}
cout << endl;
cout << "\ngquiz1.lower_bound(40) : " << *gquiz1.lower_bound(40) << endl; //40
cout << "gquiz1.upper_bound(40) : " << *gquiz1.upper_bound(40) << endl; //30
cout << "gquiz2.lower_bound(40) : " << *gquiz2.lower_bound(40) << endl; //40
cout << "gquiz2.upper_bound(40) : " << *gquiz2.upper_bound(40) << endl; //60
return 0;
}
移除multiset
中有相同值的元素
a.erase(n)
:移除multiset
中值为n的所有元素a.erase(a.find(n))
:移除multiset
中值为n的其中一个元素
#include <bits/stdc++.h>
using namespace std;
int main()
{
multiset<int> a;
a.insert(10);
a.insert(10);
a.insert(10);
cout << a.count(10) << endl; //3
a.erase(a.find(10));
cout << a.count(10) << endl; //2
a.erase(10);
cout << a.count(10) << endl; //0
return 0;
}
其它方法
Function | Definition |
---|---|
begin()/end() | 返回一个迭代器,指向multiset中的第一个元素/最后一个元素后的理论元素 |
size() | 返回multiset中的元素数量 |
max_size() | 返回multiset可以容纳的最大元素数量 |
empty() | 返回multiset是否为空 |
insert(const g) | 向multiset添加新元素g。 |
insert(iterator,const g) | 在迭代器指向的位置添加新元素“g” |
erase(iterator position) | 删除迭代器指向位置处的元素 |
erase(const g) | 从多重集合中删除值“g” |
clear() | 从多重集合中删除所有元素 |
key_comp()/value_comp() | 比较两个元素的大小以确定它们的排列顺序/比较元素大小(不常用) |
find(const g) | 如果找到元素“g”,则返回指向它的迭代器,否则返回指向末尾的迭代器 |
count(const g) | 返回multiset中与元素“g”匹配的次数 |
lower_bound(const g)/upper_bound(const g) | 返回一个迭代器,指向在multiset中第一个元素,该元素不小于/大于给定的元素g。若没有则返回一个指向multiset末尾的迭代器。 |
swap() | 交换两个multiset的内容,但集合必须是同一类型 |
emplace() | 将新元素插入multiset容器中 |
equal_range() | 返回一个迭代器对,迭代器对是容器中所有键值等于k的元素的范围。 |
emplace_hint() | 在multiset中插入新元素 |
rbegin()/rend() | 返回指向multiset中最后一个元素/第一个元素之前的理论元素的反向迭代器 |
cbegin()/cend() | 返回指向multiset中第一个元素/最后一个元素之后的常量迭代器 |
crbegin()/crend() | 返回指向multiset中最后一个元素/第一个元素之前的理论元素的反向常量迭代器 |
get_allocator() | 获取与multiset关联的分配器对象的副本,以便进行自定义的内存管理 |
4 Multimap
Multimap
与Map
类似,不同之处在于多个元素可以共享相同的键,它并不要求键-值对必须是唯一的。值得注意的一点是,Multimap
始终保持所有键按顺序排序。
基本方法
begin()
:返回指向Multimap
中第一个元素的迭代器end()
:返回指向Multimap
中最后一个元素之后理论元素的迭代器size()
:返回Multimap
中元素的数量max_size()
:返回Multimap
可以容纳的最大元素数量empty()
:返回Multimap
是否为空pair<int, int> insert(keyvalue, multimapvalue)
:向Multimap
中添加新元素
Multimap实例
#include <iostream>
#include <iterator>
#include <map>
using namespace std;
int main()
{
multimap<int, int> gquiz1;
gquiz1.insert(pair<int, int>(1, 40));
gquiz1.insert(pair<int, int>(2, 30));
gquiz1.insert(pair<int, int>(3, 60));
gquiz1.insert(pair<int, int>(6, 50));
gquiz1.insert(pair<int, int>(6, 10));
multimap<int, int>::iterator itr;
cout << "\nThe multimap gquiz1 is : ";
for (itr = gquiz1.begin(); itr != gquiz1.end(); ++itr) {
//[1,40][2,30][3,60][6,50][6,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
gquiz1.insert(pair<int, int>(4, 50));
gquiz1.insert(pair<int, int>(5, 10));
cout << "\nThe multimap gquiz1 after adding extra elements is :";
for (itr = gquiz1.begin(); itr != gquiz1.end(); ++itr) {
//[1,40][2,30][3,60][4,50][5,10][6,50][6,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
multimap<int, int> gquiz2(gquiz1.begin(), gquiz1.end());
cout << "\nThe multimap gquiz2 after assign from gquiz1 is :";
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[1,40][2,30][3,60][4,50][5,10][6,50][6,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
cout << "\ngquiz2 after removal of elements less than key=3 :";
gquiz2.erase(gquiz2.begin(), gquiz2.find(3));
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[3,60][4,50][5,10][6,50][6,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
int num;
num = gquiz2.erase(4);
cout << "\ngquiz2.erase(4) : "<< num << " removed \n "; //1
for (itr = gquiz2.begin(); itr != gquiz2.end(); ++itr) {
//[3,60][5,10][6,50][6,10]
cout << '[' << itr->first << ',' << itr->second << ']';
}
cout << endl;
//[5,10]
cout << "gquiz1.lower_bound(5) : ["<< gquiz1.lower_bound(5)->first << ','<< gquiz1.lower_bound(5)->second << ']' <<endl;
//[6,50]
cout << "gquiz1.lower_bound(5) : ["<< gquiz1.upper_bound(5)->first << ','<< gquiz1.upper_bound(5)->second << ']' <<endl;
return 0;
}
其它方法
Function | Definition |
---|---|
crbegin()/crend() | 返回一个指向multimap中最后一个元素/第一个元素之前理论元素的常数逆向迭代器 |
emplace_hint() | 在中使用hint插入元素,hint一般是表示插入的位置的迭代器 |
clear() | 移除所有元素 |
multimap empty() | 返回multimap是否为空 |
maxsize() | 返回可以容纳的最大元素数量 |
key_comp()/value_comp() | 用于获取multimap的键/键-值的比较对象,允许自定义比较规则 |
rbegin()/rend() | 返回一个指向最后一个元素/第一个元素之前理论元素的逆向迭代器 |
cbegin() and cend() | 返回一个指向第一个元素/最后一个元素之后理论元素的常数迭代器 |
swap() | 交换两个相同类型和大小的multimap容器的内容 |
size() | 返回元素的数量 |
emplace() | 插入键和其元素 |
begin()/end() | 返回一个指向multimap中第一个元素/最后一个元素之后理论元素的迭代器 |
lower_bound()/upper_bound() | 返回指向首个不小于/大于给定键值的元素的迭代器 |
count(g) | 返回multimap中与给定键值 ‘g’ 匹配的元素数量 |
erase() | 从multimap中移除给定键值 |
find(g) | 返回multimap中键值 ‘g’ 对应的元素的迭代器,没找到返回尾迭代器。 |
equal_range() | 获取一个迭代器对,该对表示与给定键值等效的所有元素的范围 |
insert() | 插入元素 |