C++总结(6):STL关联容器之set、map、multiset、multimap详解

C++中有多种种类的容器,包括:顺序容器(Sequence Containers)、关联容器(Associative Containers)、无序容器(Unordered Containers)和容器适配器(Container Adapters)。

上一篇文章介绍了顺序容器,这篇文章就来详细一下关联容器。关联容器实现了可以快速搜索的排序数据结构,具有O(log n)的复杂度。它包括setmapmultisetmultimap

文章目录

  • [1 Set](#1 Set)
  • [2 Map](#2 Map)
  • [3 Multiset](#3 Multiset)
  • [4 Multimap](#4 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中插入元素x
  • clear():从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

MultimapMap类似,不同之处在于多个元素可以共享相同的键,它并不要求键-值对必须是唯一的。值得注意的一点是,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() 插入元素
相关推荐
一颗花生米。16 分钟前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
问道飞鱼17 分钟前
Java基础-单例模式的实现
java·开发语言·单例模式
学习使我快乐0120 分钟前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
通信仿真实验室1 小时前
(10)MATLAB莱斯(Rician)衰落信道仿真1
开发语言·matlab
勿语&1 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
家有狸花2 小时前
VSCODE驯服日记(三):配置C++环境
c++·ide·vscode
dengqingrui1233 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝3 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O3 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
吾爱星辰5 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin