数据结构: map与set的简单实现

目录

map与set的模拟实现

1.基本框架

2.模拟实现map与set所需要做的事

1.使用模板 , 达到泛性编程

2.比较问题

3.迭代器

RBTree中:

operator++

operator--

4.map [ ]  的实现

5.使用普通迭代器构造const迭代器

效果


map与set的模拟实现

1.基本框架

map

set

2.模拟实现map与set所需要做的事

  1. 调用模板, 使得用map与set复用同一棵树(解决map存pair, set存key的问题)
  2. 比较问题
  3. 迭代器中, ++,--的实现(遍历二叉树)
  4. map[ ] 的实现
  5. 维护底层搜索二叉树的性质, 要使用const迭代器, set可以都用const迭代器, 但是map需要达到key不能修改, 但允许value可以修改, 所以红黑树也需要实现普通迭代器,--使得key不能修改-->map再传递pair的时候,给K加上const就行                                                -->set的iterator 是红黑树中的const_iterator && const_iterator也是const_iterator            -->map的使用了iterator 与 const_iterator                                                                         set的iterator调用的时候, 会发生隐式类型转换,  普通迭代器-->const迭代器                     如果没提供普通迭代器到const迭代器的构造会报错  --> 需要提供

1.使用模板 , 达到泛性编程

   map: kv类型   set : k类型   

map:

set:


2.比较问题

由于使用了泛性编程, RBTreeNode里面的_data类型不确定, 可能是K, 也可能是pair

--如果是K(set)的比较,不会有问题

--如果是pair(map)的比较, 比较会出现问题

pair的比较: 如果first小就小, 如果first不小, 比较second, second小就小

但我们只期望按K去比较


解决: 使用仿函数

红黑树并不知道传过来的T是K类型还是pair类型, 但是上一层知道, 于是我们给它加一个仿函数,

这个仿函数在map/set里面实现 用来获取key,然后传递给红黑树, 让其根据key来比较

像这样:

map

set


用法:

data  为T类型, 可能是K类型, 也可能是pair类型,我们将其传递给仿函数,来获取key

1.插入

2.查找

   Node* cur ->_data  为T类型, 可能是K类型, 也可能是pair类型,我们将其传递给仿函数,来获取key

  

3.迭代器

map与set的迭代器是使用红黑树内部的迭代器

1.注意: 当我们去取一个类模板的内嵌类型的时候, 前面要加一个typename

2. 原因:  因为编译器无法区分, 你取得是类型还是静态变量 

加上typename告诉编译器所取得是类型, 等该类模板实例化后, 再去找这个类型

3.示例:

map

set

框架:

RBTree中:

begin

使用最左边的节点构造迭代器

end

1.使用空节点构造迭代器(一般是最右边的节点的下一个--->是nullptr)

2.实现的时候增加哨兵位

--此时如果it走到最后一个节点,再++, 就直接走到end

--特殊处理:

优点:end--的时候, 直接到最右边的节点

operator++

左子树,  根 ,  右子树  (中序,找完右子树后,  其树就被访问完了)
思路:
1.有右子树: 就往右子树走-->找右子树的最左节点

2.没有右子树: 看是不是parent的左子树
--是的话就把parent给it
--不是的话向上调整    (调整最后没有父亲节点了,跳空)

沿着根路径, 找孩子是父亲左孩子的那个祖先


对以下情况演示:

1.该节点有右子树

2.该节点没有右子树

3.走到最后一个节点

代码:

	Self& operator++() {//1.右子树不为空,找右子树的最左节点if (_node->_right) {Node* subRL = _node->_right;while (subRL->_left) {subRL = subRL->_left;}_node = subRL;}//2.右子树为空, 找节点是父亲左孩子的祖先else {Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}

operator--

和上面基本一样,只是换了个方向: 右子树,  根 ,  左子树(该顺序访问, 走完左子树,该树就走完)

思路:

1.有左子树, 就往左子树走--->找左子树里最右边节点

2.没有左子树, 就找节点是父亲的右孩子的祖先

--如果当前节点就是父亲的右孩子,  直接把parent给it

--如果当前节点不是父亲的右孩子, 沿根路径向上调整, 找到为止(或找到p为nullptr)

   找到了就把parent给it

代码:

	Self& operator--(){//1.如果有左子树,就往左子树走,找其最右边的节点if (_node->_left) {Node* subLR = _node->_left;while (subLR->_right) {subLR = subLR->_right;}//然后把这个节点给it_node = subLR;}//2.如果没有左子树, 就找节点是父亲右孩子的祖先else {Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur) {cur = parent;parent = parent->_parent;}//然后把这个节点给it_node = parent;}return *this;}

4.map [ ]  的实现

1.修改insert的返回值为pair<iterator,bool>

--修改RBTree里Insert的返回值:

--空树插入成功

--非空树插入失败

--非空树插入成功

这里使用newnode记录以下cur节点,  下面需要对红黑树调整, cur 可能会发生改变

2.[ ]的实现

--调用RBTree里的Insert函数

--返回其second

		pair<iterator, bool> insert(const pair<const K,V>& kv){return _t.Insert(kv);}//[]的实现V& operator[](const K& key) {pair<iterator,bool> ret =  _t.Insert(make_pair(key, V()));return ret.first->second;}

5.使用普通迭代器构造const迭代器

1.问题:如果使用普通迭代器, 那么key的值会被修改, 不满足二叉搜索树性质

示例:

2.我们使用const迭代器

出现报错

--原因:发生隐式类型转换, 但我们没有提供使用普通迭代器构造const迭代器的构造函数,

转换不了, 会报错

--解决: 提供一个支持普通迭代器到const迭代器的转换

--为什么RBTree不都返回const迭代器??

---因为map与set复用的是同一个红黑树来set全用const可以, 但map允许修改V

代码:

--当Ref是T&, Ptr是T*的时候, 调用这个构造函数就是拷贝构造

--当Ref是constT& ,Ptr是constT*的时候, 调用这个构造函数就是支持普通迭代器构造const迭代器的转换

效果

代码:Map and Set/Map and Set · 朱垚/数据结构练习 - 码云 - 开源中国 (gitee.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iOS】MVC模式

MVC&#xff08;Model-View-Controller&#xff0c;模型-视图-控制器&#xff09;模式是相当古老的设计模式之一&#xff0c;ta最早出现在SmallTalk语言中。现在&#xff0c;很多计算机语言和架构都采用了MVC模式。 MVC模式概述 MVC模式是一种设计模式&#xff0c;由3部分组成…

【Spring Cloud】如何确定微服务项目的Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本

文章目录 1. 版本选择2. 用脚手架快速生成微服务的pom.xml3. 创建一个父工程4. 代码地址 本文描述如何确定微服务项目的Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本。 1. 版本选择 我们知道Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本选择一致性非常重…

【ML】cheatsheet

LR 原理与面试题目DT, Adaboost, GBDT, xgboost 原理 细节 与 例子 https://www.cnblogs.com/createMoMo/p/12635709.html xgboost挺详细的算法原理与例子 https://zhuanlan.zhihu.com/p/660468945 着重lightgbm就xgboost的改善方向 https://zhuanlan.zhihu.com/p/366952043机器…

《计算机视觉中的多视图几何》笔记(14)

14 Affine Epipolar Geometry 本章主要是在仿射摄像机的情况下重新考虑对极几何&#xff0c;也就是仿射对极几何。 仿射摄像机的优点是它是线性的&#xff0c;所以很多最优化算法可以用线性代数的知识解决。如果是一般的投影摄像机&#xff0c;很多算法就不是线性的了&#x…

IDEA 新版本设置菜单展开

使用了新版本的IDEA 新UI后&#xff0c;常用的file&#xff0c;view&#xff0c;菜单看不见了&#xff0c;不太适应&#xff0c;找了一下&#xff0c;有个配置可以修改。 打开settings里面把show main menu in a separate toolbar勾选上&#xff0c;应用保存就可以了

CSS3属性详解(一)文本 盒模型中的 box-ssize 属性 处理兼容性问题:私有前缀 边框 背景属性 渐变 前端开发入门笔记(七)

CSS3是用于为HTML文档添加样式和布局的最新版本的层叠样式表&#xff08;Cascading Style Sheets&#xff09;。下面是一些常用的CSS3属性及其详细解释&#xff1a; border-radius&#xff1a;设置元素的边框圆角的半径。可以使用四个值设置四个不同的圆角半径&#xff0c;也可…

flink中使用GenericWriteAheadSink的优缺点

背景 GenericWriteAheadSink是flink中提供的实现几乎精确一次输出的数据汇抽象类&#xff0c;本文就来看一下使用GenericWriteAheadSink的优缺点 GenericWriteAheadSink的优缺点 先看一下GenericWriteAheadSink的原理图 优点&#xff1a; 几乎可以精确一次的输出&#xf…

在Word中,图片显示不全

在今天交作业的时候&#xff0c;发现了一个非常SB的事情&#xff0c;把图片复制过去显示不完全&#xff1a; 使用文心一言查看搜索了一下&#xff0c;发现可能是以下几种原因&#xff1a; 图片所在行的行高设置不正确。可以重新设置行高&#xff0c;具体步骤包括打开图片显示…

【网络编程】基于epoll的ET模式下的Reactor

需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;新用户首次下单享超低折扣。 目录 一、Reactor介绍 二、基于epoll的ET模式下的Reactor计算器代码 1、Tcp…

[计算机入门] 应用软件介绍(娱乐类)

3.21 应用软件介绍(娱乐类) 3.21.1 音乐&#xff1a;酷狗 音乐软件是一类可以帮助人们播放、管理和发现音乐的应用程序。它们提供了丰富的音乐内容&#xff0c;用户可以通过搜索、分类浏览或个性化推荐等方式找到自己喜欢的歌曲、专辑或艺术家。音乐软件还通常支持创建和管理…

Python基础入门例程1-NP1 Hello World!

描述 将字符串 Hello World! 存储到变量str中&#xff0c;再使用print语句将其打印出来。 输入描述&#xff1a; 无 输出描述&#xff1a; 一行输出字符串Hello World! 解答&#xff1a; str "Hello World!" print(str) 解释说明&#xff1a; 赋值变量&…

Metabase:简单快捷的商业智能与数据分析工具 | 开源日报 No.61

moby/moby Stars: 66.8k License: Apache-2.0 Moby 是一个由 Docker 创建的开源项目&#xff0c;旨在实现和加速软件容器化。它提供了工具包组件的“乐高集”&#xff0c;可以将它们组装成基于容器的自定义系统的框架。组件包括容器生成工具、容器注册表、业务流程工具、运行时…

互联网Java工程师面试题·Java 面试篇·第四弹

目录 59、我们能自己写一个容器类&#xff0c;然后使用 for-each 循环码&#xff1f; 60、ArrayList 和 HashMap 的默认大小是多数&#xff1f; 61、有没有可能两个不相等的对象有有相同的 hashcode&#xff1f; 62、两个相同的对象会有不同的的 hash code 吗&#xff1f; …

[AUTOSAR][诊断管理][ECU][$14] 清除诊断相关信息

文章目录 一、简介(1)应用场景(2)清除DTC原理(3) 请求格式二、示例代码(1) 14_cls_dtc_info.c三、 常见bug大揭秘一、简介 根据ISO14119-1标准中所述,诊断服务14主要用于Client向Server(ECU)请求清除诊断相关信息。 (1)应用场景 一般而言,14诊断服务,主要应用场景…

Kubernetes 通过 Deployment 部署Jupyterlab

概要 在Kubernetes上部署jupyterlab服务&#xff0c;链接Kubernetes集群内的MySQL&#xff0c;实现简单的数据开发功能。 前置条件 镜像准备&#xff1a;自定义Docker镜像--Jupyterlab-CSDN博客 MySQL-Statefulset准备&#xff1a;StatefulSet 简单实践 Kubernetes-CSDN博客…

​​​​​​​2022年上半年 软件设计师 上午试卷(1-32)

以下关于冯诺依曼计算机的叙述中&#xff0c;不正确的是 &#xff08;1&#xff09; 。 &#xff08;1&#xff09; A. 程序指令和数据都采用二进制表示 B. 程序指令总是存储在主存中&#xff0c;而数据则存储在高速缓存中 C. 程序的功能都由中央处理器&#xff08;CPU&…

5、k8s部署Nginx Proxy Manager

前言 Nginx-Proxy-Manager 是一个基于 Web 的 Nginx 服务器管理工具&#xff0c;它允许用户通过浏览器界面轻松地管理和监控 Nginx 服务器。通过 Nginx-Proxy-Manager&#xff0c;可以获得受信任的 SSL 证书&#xff0c;并通过单独的配置、自定义和入侵保护来管理多个代理。用…

Linux自有服务与软件包管理

服务是一些特定的进程&#xff0c;自有服务就是系统开机后就自动运行的一些进程&#xff0c;一旦客户发出请求&#xff0c;这些进程就自动为他们提供服务&#xff0c;windows系统中&#xff0c;把这些自动运行的进程&#xff0c;称为"服务" 举例&#xff1a;当我们使…

Linux:用户和权限

Linux&#xff1a;用户和权限 1. 认知root用户1.1 root用户&#xff08;超级管理员&#xff09;1.2 su和exit命令1.3 sudo命令1.3.1 为普通用户配置sudo认证 2. 用户、用户组管理2.1 用户组管理2.2 用户管理2.3 getent命令 3. 查看权限控制3.1 认知权限信息3.1.1 案例 4. 修改权…

rust学习——引用与借用(references-and-borrowing)

引用与借用&#xff08;references-and-borrowing&#xff09; 先看一个返回参数的所有权的代码 fn main() {let s1 String::from("hello");let (s2, len) calculate_length(s1);println!("The length of {} is {}.", s2, len); }fn calculate_length(…