c++ vs2019 cpp20规范的STL库的map与multimap源码分析,及几个成员函数分析,补充 insert()的返回值类型,

文章讲述了红黑树作为平衡二叉树的特性,与AVL树的区别,特别提到B站可雷曼土大师的系列教程对理解和学习STl中map数据结构的帮助,强调了map中使用父指针而非递归的特点。

(1 探讨一) map就是一个红黑树。
标准平衡二叉树,要求左右子树的高度差不超过1 。红黑树只要求左右子树的高度差不超过一倍即可。兼顾了树平衡与效率。避免了AVL树的频繁调整树平衡。
b站 的“可雷曼土”大师,讲红黑树的理论讲的很透彻,再结合看代码,才可以看懂。总共五六集。很全面透彻,没这位老师的讲解,我是学不会
在这里插入图片描述

自己画的vs2019 的STl的map的数据结构。从网上找图,暂时没找到。先凑合一下。
二叉树里有很多递归,但map实现上多了父指针,就用不上递归了,需要的时候,可以直接回溯。

(2 探讨二) 给出 map 模板的内存代码结构

在这里插入图片描述
(3 探讨三) 接着结合应用,多注释一些 map 的成员方法。因为二叉树,红黑树 map 的数据结构异常复杂,其成员函数也不太好理解,特额外注释以下:

在这里插入图片描述

上图中的 map 的键值对,键是 int ,值是 list 链表。

首先分析 find () 成员函数:

在这里插入图片描述

下图继续解释 _Find() 的返回值的类型:

在这里插入图片描述

接着分析 map 的 end() 函数:

在这里插入图片描述

上图也解释了为什么应用代码里有 迭代器 iter != allFamily . end() 这么比较的原因,这么比较是合理的。迭代器的比较,只要指向相同的容器,包含相同的指针,则这俩迭代器就认为是相同的。如下图:

在这里插入图片描述

(4 探讨四) 继续分析上面的应用程序:

在这里插入图片描述

首先给出 vs2019 STL 标准库里结构 pair 的定义:

在这里插入图片描述

接着进入 map 的迭代器源码,分析 * 运算符函数 与 -> 运算符函数的定义:

在这里插入图片描述

下图给出 pointer_to() 的定义:

在这里插入图片描述

至此,我们分析完了 iter -> second . push_back ( player ) ; 这行代码, iter -> second 返回的是键值对中的第二个值,在本例子中就是那个 list 链表,而 list 是支持 push_back () 的插入操作的。

(5 探讨五) 接着分析 map 的插入函数:

在这里插入图片描述

首先由易到难,给出 全局函数 make_pair() 的定义(因为应聘前还有很多书要看,时间不够了,就不对 map 做深入分析了,只能对函数调用链做简单的浅层次的分析了):

在这里插入图片描述

接着给出 map 的 insert ( ) 函数的定义:

在这里插入图片描述

下图给出 红黑树的插入操作对应的函数:

在这里插入图片描述

++后来的补充,本函数 insert() 的返回值也应该被检查,以防止插入失败

在这里插入图片描述

++ 不看源码了,展示下 例子验证一下算了,以后补充源码:

在这里插入图片描述

++ 以及,给出其返回值的测试与学习

在这里插入图片描述

(6 探讨六) 继续分析 map 的 [ ] 运算符函数:

在这里插入图片描述

首先给出其源码:

在这里插入图片描述

接着给出 [ ] 运算符函数调用的 _Try_empayce ( ) 函数的定义:

在这里插入图片描述

而且源码显示 [ ] 运算符函数与 at () 函数是等价的( at ( ) 函数的语义更明显。但 [ ] 的表示方式更熟悉):

在这里插入图片描述

( 7 探讨七) 接着分析 map 的成员函数 clear() ,此函数实际定义在 map 的父类中,我们看看 clear() 函数的内容:

在这里插入图片描述

对注释展开一下,是可以找到释放树节点内存的语句的。二叉树直接存储了键值对,而不是指向键值对的指针。

在这里插入图片描述

接着我们看下应该有 与 clear() 类似功能的 map 的析构函数 : ~ map()。源码可见,没有直接定义函数 ~ map()。析构的主要功能由其父类实现了。析构的顺序与构造相反:析构函数体,自己的对象类型成员的析构,调用父类的析构函数。clear () 只是释放了树中的节点,还保留了树根,以便于再次重新插入节点,而且也保留了容器代理,但在析构函数中,为了彻底回收内存,连树根节点与代理也要处理,这些在堆中分配的内存。

在这里插入图片描述

以及

在这里插入图片描述

(8)来不及复习这个 红黑树的复杂源码了,举例验证其的在删除操作中的迭代器的使用

在这里插入图片描述

++ 源代码版本:

#include <iostream>
// #include <map>
#include <map>
using namespace std; // 本例子是为了验证删除函数的语义是否跟简单的 list 里保持一致

int main() // 本例中编写的 for 的循环条件,也很精妙!!
{	// 本测试的意图是删除红黑树里所有的 2 ,且 2 既在开头也在链尾
	multimap<int, int> myList{ {2,1},{2,2},{2,3},{2,4},{2,5},{7,8},{9,2},{2,2} };

	auto iterBegin = myList.begin(), iterEnd = myList.end();

	for (auto iter = iterBegin; iter != iterEnd; ) //省略递增条件
		if (iter->first == 2)
			iter = myList.erase(iter);
		else
			iter++;

	for (auto iter = myList.begin(); iter != iterEnd; iter++)
		cout << iter->first << "   ";

	cout << endl;

	return 0;
}

(9)

谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangzhangkeji

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值