C++:map和set重点解析

目录

1.关联式容器

[2.set 容器](#2.set 容器)

3.map

[4. multiset 容器](#4. multiset 容器)


1.关联式容器

序列式容器:queue、vector、list,按照插入顺序存储数据,查找数据需要遍历时间复杂度为O(n)

今天说有序关联容器 map和set,是关联式容器的一种;map和set的底层是红黑树。而红黑树是基于搜索二叉树改进的。

关联式容器:数据之间有关联,之间符合一定的规则;便于查找。存储的不再是单一的元素,而是<key,value>的键值对,查找比较方便,时间复杂度为O(logN)量级。

关联式容器之间的规则依靠关键字(key)建立了逻辑关系,相比于序列式容器更加高效。

键值对 可以理解为一个结构有两个值 一个是key一个value,每个key和value一 一对应;C++中一般使用pair来表示键值对,

pair

cpp 复制代码
template <class T1, class T2> struct pair;

first 为 key second 为 value

2.set 容器

set - C++ 参考

上面的连接为set的介绍,

cpp 复制代码
template < class T,                        // set::key_type/value_type
           class Compare = less<T>,        // set::key_compare/value_compare
           class Alloc = allocator<T>      // set::allocator_type
           > class set;

注意

  1. set 存储的数据就是 key,按照 key 建立有序联系
  2. set 的 key 和 value 就是同一个模板参数,访问 set 的 value 就是访问 key 值。暂时理解为 set 中只存储一份 key (打个断点不确定)。
  3. set 不允许修改 key 值,因为会破坏以 key 值建立的逻辑关系;由于 value 和 key 是同一个值,因此 二着均不可修改。
  4. 不存储重复的值,底层为搜索二叉树,具有排序和去重的功能
  5. set 的 find 函数时间复杂度为 Olog(N),犹豫序列式容器的O(N)

3.map

map - C++ 参考

cpp 复制代码
template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

介绍

  1. map 是关联容器,根据关键值 key 进行排序存储键值和 value 组合成的元素
  2. 使用 pair 将 key 和 value 绑定在一起,然后存储。
  3. map 支持下标访问,可以通过 key 访问 value,下面我们详细说
  4. 底层为红黑树,和 set 一样,通过 key 值排序,然后存储pair。
  5. key 值是无法修改的,但是 value 是可以修改的

map的插入

cpp 复制代码
    map<string, string> mp;
	pair<string, string> kv = { "string","字符串" };
	mp.insert(kv);
	// C++11 多参数的构造函数隐式类型转换
	mp.insert({"insert","插入"});
	// C++98
	mp.insert(make_pair( "erase","消除"));
	// 强制类型转换
	mp.insert(pair<string, string>("sort", "排序"));

其他函数比较简单,这里说一下让 operator[ ]函数

operator[ ]的使用等价于 下面的结构

cpp 复制代码
(*((this->insert(make_pair(k,mapped_type()))).first)).second

下面的这段程序调用的是insert函数,

cpp 复制代码
(this->insert(make_pair(k,mapped_type()))

insert的返回值为 pair<iterator,bool>,相当于相面的程序

cpp 复制代码
(*(pair<iterator,bool>.first)).second
cpp 复制代码
(*(iterator).second

然后我们在看看迭代器

second 就是 value值,所以 [ ] 可以访问对应 key 的 value。并且具有插入的作用,看下述的程序

cpp 复制代码
void testmap3()
{
	map<string, string> dict;
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("insert", "插入"));
	dict["erase"];          //插入数据;
	dict["erase"] = "删除";  // 修改
	cout << dict["erase"] << endl; 
	dict["erase"] = "xxxxxx";  //修改
	dict["map"] = "映射、地图"; //插入+修改

	for (const auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

4. multiset 容器

cpp 复制代码
template < class T,                        // multiset::key_type/value_type
           class Compare = less<T>,        // multiset::key_compare/value_compare
           class Alloc = allocator<T> >    // multiset::allocator_type
           > class multiset;

介绍 性质和set一样。但是不同的是可以存储多个相同key值。

测试如下,主要注意 count函数,返回相同 key 值出现的数量; equal_range函数,返回pair,一个等于值一个大于其的值,可以用于删除等于key的全部的值,lower_bound函数返回大于等于这个值得迭代器,upper_bound返回大于这个值得迭代器。

cpp 复制代码
void testset2()
{
	multiset<int> ms;
	int arr[] = { 1,2,88,8,7,3,5,9674,9,148,51,5,589,451,561,5,84,6,66,161,8 };

	for (const auto& e : arr)
	{
		ms.insert(e);
	}
	cout << ms.size() << endl;
	for (auto& e : ms)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "8:"<<ms.count(8) << endl;
	cout << "5:" << ms.count(5) << endl;
	auto ret = ms.equal_range(5);

	cout << *(ret.first) << endl;
	cout << *(ret.second) << endl;

	ms.erase(ret.first, ret.second);
	for (auto& e : ms)
	{
		cout << e << " ";
	}
	cout << endl;

}
相关推荐
FQNmxDG4S18 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人18 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang18 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全18 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje19 小时前
Java语法进阶
java·开发语言·jvm
汉克老师19 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
老前端的功夫19 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_4352879219 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
止语Lab19 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
yaoxin52112319 小时前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python