改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现

改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现

容器map/set的底层是红黑树,这一篇详解红黑树如何封装实现map/set。

1.map/set设计的巧妙之处

map是key/value类型,set是key类型,两个冲突的参数类型,是如何由红黑树封装而成?



暴力思路:两个红黑树,一个kv,一个k。可是这样代码复用率极低,维护成本高



源码思路:利用 键提取器——仿函数 提取kv、k的key,用一颗红黑树实现map,set



C语言一般用函数指针,但是它十分麻烦,C++有了仿函数就很方便

接下来在红黑树基础上封装map和set

2.map和set的实现

2.1map和set的基本框架 + 原红黑树结构变化

map是key、value结构,set是key结构:

 既然我们要用一个红黑树封装实现map和set,那传的参数就得通用:







原本是K,V结构,现在,要改成通用的,就用T吧







T根据需要,可选择传pair<K,V>,也可以是K:(原来是K,V,参数是kv)

然后根据上面,各自写一个仿函数,用于控制红黑树底层获取Key的行为

上层传仿函数,下层需要新增一个模板参数来接收:

2.2Insert

根据上面,原本是KV结构的红黑树,那Insert自然传的是pair

现在传data就行:data类型可能是pair<K,V>,也可能是Key,根据传的不同,创建仿函数对象,去获取它的Key:

Insert后面的部分,反正涉及到获取Key比较大小,就用仿函数

这样就形成一个回调。

2.3Find

Find是用Key比较,那_data类型可能是Key,也可能是pair<K,V>,那同样需要仿函数获取Key

map复用红黑树的Insert,Find



set复用红黑树的Insert,Find

2.4map和set的迭代器Iterator

map和set的迭代器都是由红黑树的迭代器封装而成,源码中有体现。源码写的迭代器十分复杂,包含了继承关系,我们就不写那么复杂。

了解到前面容器的迭代器实现,不难猜红黑树的迭代器也是用一个类封装,再通过重载运算符,使迭代器能像指针一样访问。

这里难点是++和--的实现。红黑树是一种二叉搜索树,走中序遍历输出结果有序。之前使用map和set也提到是这样,得出结论:红黑树迭代器也是走中序遍历:左根右

那begin返回中序遍历第一个结点(最左结点),end返回空结点(最右结点的一个是空,下面)

迭代器实现++ 和 -- ,只需要注意局部。++返回中序下一个节点,--返回上一个,局部解决了,全局就解决了。但是++和--的情况很多,这也就是它的难点,不是逻辑难点,是代码难点。举例子:

根据中序:左根右,可以推断,begin的下一个就是15节点

因为走到10节点,说明当前子树 左,根都遍历完了,就剩右子树,中序访问右子树,就必须先访问其最左节点,15没有最左节点(本身就是右子树的最左节点),那++it的结果就是15节点

这里呢? it遍历到18节点,说明 左与根 都遍历完了,++it就是遍历右子树的最左节点(中序第一个),也就是25节点

那如果右子树为空呢?中序遍历升序,可以知道15的下一个是18,怎么得来?

15的右子树为空,15也已经遍历过,说明当前15的子树遍历完,那15要往上找祖先。15作为10的右子树,说明10也已经遍历完(右子树最后遍历),那10也要往上找祖先。

若10还是祖先的右子树,就还得继续找,找到根的父亲还没找到,或者找到,右父亲,停止。

若10是祖先的左子树,说明才刚遍历完祖先的左子树,那下一个就是该祖先,根

这里同理,++若右子树为空,就得向上找右父亲,25的右父亲直接就是30,得出答案。

2.4.1实现迭代器(重点是++与--)

红黑树内部使用迭代器: 

上层(map和set)复用红黑树的迭代器

模板还未实例化,取其中成员类型时,需要typename:告诉是个类型,后面实例化再去找。

迭代器的 --  和 ++ 完全对称,找左父亲,end前一个为最右结点。

2.5 Key不能被修改的问题

对于set,它的key是不能被修改的,但是这里的迭代器还是能修改它。

可以修改后,这棵树就失去意义了, 所以我们要解决这个Key被修改的问题。

为了让它不被修改,最简单的就是这样:

上层传递的const Key给红黑树,因为被const修饰,所以K将不会被修改,从源头解决问题。

typedef这里的声明也需要加上const,不然会出现很多模板特有的意义不明确的报错。

对于map,pair里的Key也不容被修改,那就同理:

2.6修改Find返回值为Iterator,实现统计次数功能

2.7修改Insert返回值为pair<Iterator,bool>,实现operator[ ]

map和set那节,讲过这个[ ]的使用和底层

newnode保存新增结点cur(因为插入过程设计旋转加变色,向上更新,最后的cur不一定是新增)

解决完Insert,接下来就实现operator[ ]:

首先插入Key,如果插入失败,说明存在,flag为false,it是已存在节点,最后返回value

                        如果插入成功,说明不存在,flag为true,it是新增结点,最后返回value

外层对value([ ]的返回值)++,即可统计次数,不用那么麻烦。

j

2.8红黑树的析构函数

map和set的析构函数会调用红黑树的析构,所以不用写他们的。注意后序遍历析构

Read more

Flutter 三方库 posix 的鸿蒙化适配指南 - 掌控底层系统调用、文件权限管理实战、鸿蒙级系统级工具专家

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 posix 的鸿蒙化适配指南 - 掌控底层系统调用、文件权限管理实战、鸿蒙级系统级工具专家 在鸿蒙跨平台应用开发中,当我们需要实现精密的文件权限操控(如 chmod)、获取系统级用户信息或是管理进程间的信号(Signals)时,高层的 Dart SDK 有时无法提供足够细粒度的控制。如果你需要一种接近 C 语言、直接与鸿蒙内核(Kernel)对话的能力。今天我们要深度解析的 posix——一个旨在为 Dart 提供标准可移植操作系统接口(POSIX)支持的高性能库,正是帮你接管“系统底层主权”的关键插件。 前言 posix 是一套对底层 C 库函数的轻量级封装。它通过 Dart FFI 机制,让你能像写

By Ne0inhk
Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案

Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案 前言 在鸿蒙(OpenHarmony)生态的分布式多媒体协作、工业设备故障图片上报以及需要频繁处理大量音频/视频附件的专业级应用开发中,“非结构化数据与 SQL 逻辑的一致性同步”是决定应用能否在大规模复杂场景下存活的技术深水区。面对一条已经同步成功的“设备巡检记录”。如果其关联的“高清故障原图”因为同步时机错位、由于存储空间不足导致的本地缓存被回收,或者是在鸿蒙手机与平板之间由于同步策略不同步导致的文件路径失效。那么不仅会导致用户在查看详情时看到令人沮丧的“附件丢失”占位图,更会严重削弱政务类资产审计的底层严密性。 我们需要一种“逻辑关联、物理对齐”的附件治理艺术。 powersync_attachments_helper 是一套专为 PowerSync 设计的附件同步

By Ne0inhk

Flutter 组件 pair 适配鸿蒙 HarmonyOS 实战:结构化元组治理,构建轻量级双元数据模型与跨层传递架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 pair 适配鸿蒙 HarmonyOS 实战:结构化元组治理,构建轻量级双元数据模型与跨层传递架构 前言 在鸿蒙(OpenHarmony)生态迈向多维数据感知、涉及高频函数返回值传递、两元坐标互操作及复杂状态标识返回的背景下,如何以最轻量化的方式实现数据的“成对化”封装,已成为提升代码整洁度与系统运行效率的“工程润滑剂”。在鸿蒙设备这类强调 AOT 极致性能与低内存开销的环境下,如果应用为了简单的双元数据(如:经纬度、错误码+消息)而动态创建大量繁琐的单次使用类(POJO),由于由于对象头开销与 GC 压力,极易由于由于“类爆炸”导致内存碎片的堆积。 我们需要一种能够支持强类型泛型、具备不可变属性且无需显式类定义的元组治理方案。 pair 为 Flutter 开发者引入了源自 C++ 与 Java 标准库经典语义的“

By Ne0inhk
Flutter for OpenHarmony:Flutter 三方库 redux_epics — 优雅管理鸿蒙状态管理中的异步副作用(适配鸿蒙 HarmonyOS Next ohos)

Flutter for OpenHarmony:Flutter 三方库 redux_epics — 优雅管理鸿蒙状态管理中的异步副作用(适配鸿蒙 HarmonyOS Next ohos)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 Flutter for OpenHarmony:Flutter 三方库 redux_epics — 优雅管理鸿蒙状态管理中的异步副作用(适配鸿蒙 HarmonyOS Next ohos) 在构建大型跨平台应用时,状态管理的严谨性直接决定了项目的可维护性。Redux 以其单向数据流和不可变状态锁定了许多开发者的心。然而,纯粹的 Redux 加速器(Reducer)必须是同步且无副作用的函数,这给处理异步网络请求、文件读写等副作用带来了挑战。 在 Flutter for OpenHarmony 开发中,redux_epics 结合 RxDart 的强大处理能力,为我们提供了一个基于“流”的副作用管理方案。今天,我们将实战如何利用 Epics 在鸿蒙应用中优雅地编排复杂的异步生命周期。 一、为什么需要 Epics? 1.

By Ne0inhk