二叉查找树的应用 —— K模型和KV模型
文章目录
- 前言
- 1. K模型
- 2. KV模型
- 🍑 构建KV模型的树
- 🍑 英汉词典
- 🍑 统计水果出现的次数
- 3. 总结
前言
在上一篇文章中,我们进行了二叉查找树的实现(文章链接),那么今天主要探讨一下二叉查找树的应用
1. K模型
K 模型即只有 key 作为关键码,结构中只需要存储 Key 即可,关键码即为需要搜索到的值。
比如:给一个单词 word,判断该单词是否拼写正确,具体方式如下:
- 以单词集合中的每个单词作为 key,构建一棵二叉查找树
- 在二叉查找树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
其实这个 K 模型就是上一篇文章中,我们实现的二叉查找树。
2. KV模型
所谓 KV 模型就是每一个关键码 key,都有与之对应的值 Value,即 <Key, Value> 的键值对。
这种方式在现实生活中非常常见:比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文 <word, chinese>就构成一种键值对;
再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是 <word, count> 就构成一种键值对。
下面我们就构造一个 KV 模型的二叉查找树,然后用这棵树来做一些应用。
🍑 构建KV模型的树
我这里直接用递归的方式实现整颗树,需要添加一个模板参数 Value,另外对于查找函数 Find 的返回值就不能写成 bool 类型了,而是需要写成 Node* 类型,因为 Key 不能被修改,但是我们可以通过返回的节点类型来修改 Key 对应的 Value。
代码实现
// KV模型
namespace key_value
{ // 节点类template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left; // 左指针BSTreeNode<K, V>* _right; // 右指针K _key; // 关键码V _value; // 对应的值// 构造函数BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};// 二叉查找树类template<class K, class V>class BSTree{typedef BSTreeNode<K, V> Node;public:// 中序遍历void InOrder(){_InOrder(_root);cout << endl;}// 查找函数Node* FindR(const K& key){return _FindR(_root, key);}// 插入函数// 注意:这里除了要插入key,还要插入对应的valuebool InsertR(const K& key, const V& value){return _InsertR(_root, key, value);}// 删除函数(只需要删除key即可)bool EraseR(const K& key){return _EraseR(_root, key);}private:// 删除函数(递归删除子函数)bool _EraseR(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else{Node* del = root;// 删除if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{Node* minRight = root->_right;while (minRight->_left){minRight = minRight->_left;}swap(root->_key, minRight->_key);return _EraseR(root->_right, key);}delete del;return true;}}// 插入函数(递归插入子函数)bool _InsertR(Node*& root, const K& key, const V& value){if (root == nullptr){root = new Node(key, value);return true;}if (root->_key < key)return _InsertR(root->_right, key, value);else if (root->_key > key)return _InsertR(root->_left, key, value);elsereturn false;}// 查找函数(递归查找子函数)Node* _FindR(Node* root, const K& key){if (root == nullptr)return nullptr;if (root->_key < key){return _FindR(root->_right, key);}else if (root->_key > key){return _FindR(root->_left, key);}else{return root;}}// 中序遍历(递归遍历子函数)void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}private:Node* _root = nullptr;};
}
🍑 英汉词典
用这棵树实现一个简单的英汉词典 dict,可以通过英文找到与其对应的中文。
以 <单词, 中文含义> 为键值对构造二叉查找树时,二叉查找树需要进行键值对的比较,并且只需要比较 Key,查询英文单词时,只需给出英文单词,就可快速找到与其对应的 key。
代码实现
void TestBSTree1()
{BSTree<string, string> ECDict;ECDict.InsertR("root", "根");ECDict.InsertR("string", "字符串");ECDict.InsertR("left", "左边");ECDict.InsertR("insert", "插入");ECDict.InsertR("erase", "删除");ECDict.InsertR("right", "右边");cout << "请输入要查找的单词: ";string str; // 输入要查找的单词while (cin >> str){auto ret = ECDict.FindR(str);if (ret != nullptr){cout << "对应的中文:" << ret->_value << endl; // 如果单词存在,输出对应的中文}else{cout << "无此单词,请重新输入" << endl; // 如果单词不存在}}
}
可以看到,当我们输入树中存在的单词时,就会显示对应的中文,如果单词不存在,就不会显示。

如果我们要修改某个单词的中文也是可以的,只需要修改节点指向的 Value 即可。
🍑 统计水果出现的次数
KV 模型的二叉树还可以用来统计某个元素出现的次数。
比如下面有一组水果,现在我需要统计水果出现的次数,并输出。
代码实现
void TestBSTree2()
{string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };// 水果出现的次数BSTree<string, int> countTree; // key是字符串; value是次数for (const auto& str : arr){auto ret = countTree.FindR(str); // 查找该水果是否存在if (ret == nullptr) // 如果该水果不存在{countTree.InsertR(str, 1); // 就插入到树中,并把次数置为1(出现了一次)}else // 如果该水果存在{ret->_value++; // 就修改value}}// 打印结果countTree.InOrder();
}
可以看到水果的次数已经被统计出来了

3. 总结
对于 K 模型的二叉查找树上节课我们已经说过了,它有很多缺点,后面的 AVL树 就是在它的基础上进行优化的,那么与之对应的就是 STL 当中的 set 容器,它的底层就是一颗 K 模型的二叉查找树。
对于 KV 模型的二叉查找树,它与之对应的是 STL 当中的 map 容器,它的底层是一颗 KV 模型的二叉查找树。
相关文章:
二叉查找树的应用 —— K模型和KV模型
文章目录前言1. K模型2. KV模型🍑 构建KV模型的树🍑 英汉词典🍑 统计水果出现的次数3. 总结前言 在上一篇文章中,我们进行了二叉查找树的实现(文章链接),那么今天主要探讨一下二叉查找树的应用…...
深度学习实战(11):使用多层感知器分类器对手写数字进行分类
使用多层感知器分类器对手写数字进行分类 1.简介 1.1 什么是多层感知器(MLP)? MLP 是一种监督机器学习 (ML) 算法,属于前馈人工神经网络 [1] 类。该算法本质上是在数据上进行训练以学习函数。给定一组特征和一个目标变量&#x…...
ThingsBoard-警报
1、使用 IoT 设备警报 ThingsBoard 提供了创建和管理与您的实体相关的警报的能力:设备、资产、客户等。例如,您可以将 ThingsBoard 配置为在温度传感器读数高于某个阈值时自动创建警报。当然,这是一个非常简化的案例,实际场景可能要复杂得多。 2、主要概念 下面让我们回…...
如何去阅读源码,我总结了18条心法
在聊如何去阅读源码之前,先来简单说一下为什么要去阅读源码,大致可分为以下几点原因:最直接的原因,就是面试需要,面试喜欢问源码,读完源码才可以跟面试官battle提升自己的编程水平,学习编程思想…...
排序:归并排序
一、归并 li[2,4,5,7,//1,3,6,8]#归并的前提是必须两部分排好序 def merge(li,low,mid,high):ilowjmid1ltmp[]while i<mid and j<high: #只要左右两边都有数if li[i]<li[j]:ltmp.append(li[i])i1else:ltmp.append(li[j])j1#while执行完,肯定有一部分没数…...
Allegro172版本线到铜皮不按照设定值避让的原因和解决办法
Allegro172版本线到铜皮不按照设定值避让的原因和解决办法 用Allegro做PCB设计的时候,有时会单独给某块铜皮附上线到铜皮额外再增加一个数值,如下图 在规则的基础上,额外再避让10mil 规则避让line到铜皮10.02mil 额外设置多避让10mil,避让的结果却是30.02mil,正确的是20.…...
小白该从哪方面入手学习大数据
大数据本质上是海量数据。 以往的数据开发,需要一定的Java基础和工作经验,门槛高,入门难。 如果零基础入门数据开发行业的小伙伴,可以从Python语言入手。 Python语言简单易懂,适合零基础入门,在编程语言…...
尚医通(十)数据字典加Redis缓存 | MongoDB
目录一、Redis介绍二、数据字典模块添加Redis缓存1、service_cmn模块,添加redis依赖2、service_cmn模块,添加Redis配置类3、在service_cmn模块,配置文件添加redis配置4、通过注解添加redis缓存5、查询数据字典列表添加Redis缓存6、bug&#x…...
为什么我们不再发明编程语言了?
上个世纪,数百种编程语言被发明出来,但是进入21世纪,当我们都进入互联网时代时,只剩那么寥寥几个了。 如果你翻一下TIOBE得编程语言排行榜,就会发现20年来,上蹿下跳的就是那几张老面孔:C , Java…...
预处理指令详解
预处理指令详解**1.预定义符号****2.#define****2.1 #define 定义标识符****2.2 #define 定义宏****2.3 #define 替换规则****2.4 #和##****#的作用****##的作用****2.5 带副作用的宏参数****2.6 宏和函数的对比****宏和函数对比图****2.7 命名约定****3.#undef**4.条件编译4.1…...
Redis
一.认识NoSQL 1.SQL 关系型数据库 结构化: 定义主键,无符号型数据等关联的:结构化表和表之间的关系通过外键进行关联,节省存储空间SQL查询:语法固定 SELECT id,name,age FROM tb_user WHERE id1 ACID 2.NoSQL 非关系型数据库 Re…...
Elasticsearch5.5.1 自定义评分插件开发
文本相似度插件开发,本文基于Elasticsearch5.5.1,Kibana5.5.1 下载地址为: Past Releases of Elastic Stack Software | Elastic 本地启动两个服务后,localhost:5601打开Kibana界面,点击devTools,效果图…...
4.4 序列化与反序列化
文章目录1.概述2.特点/应用场景3.涉及到的流对象4.代码实现序列化与反序列化4.1 步骤1:创建学生类Student24.2 步骤2:创建序列化测试类5.测试案例中常见的几种编译错误类型6.为什么反序列化版本号需要与序列化版本号一致?7.自动提示 生成UID …...
647. 回文子串 516. 最长回文子序列
647. 回文子串 方法一:动态规划 dp[i][j]:[i,j]范围的下标字符串s是否为回文子串 遍历字符串,每次判断s[i]与s[j]是否相等 ①若相等,j-i0 即单个字符串s[i],那么一定为回文子串,赋值为1 ②若相等,j-i1…...
实用小妙招
记录一些实用小妙招,都是收藏夹里收藏的各种文章,总结在一起,持续更新 实用小妙招LinuxUbuntu修改终端语言安装 Node.js (nvm)git 记住账号密码WSL迁移默认用户修改Linux Ubuntu 修改终端语言 apt update apt install -y language-pack-zh…...
别让猴子跳回背上
1.管理者的贡献来自于他们的判断力与影响力,而非他们所投入的个人时间与埋头苦干 2.管理者的绩效表现则是许多人群策群力的结果 3.管理者的时间管理: 老板占用的时间;组织占用的时间;自己占用的时间;外界占用的时间; 4.管理者的策略在于增加自己的时间,…...
数据结构 | 线性表
🔥Go for it!🔥 📝个人主页:按键难防 📫 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 📖系列专栏:数据结构与算法 ὒ…...
Deepwalk深度游走算法
主要思想 Deepwalk是一种将随机游走和word2vec两种算法相结合的图结构数据的挖掘算法。该算法可以学习网络的隐藏信息,能够将图中的节点表示为一个包含潜在信息的向量, Deepwalk算法 该算法主要分为随机游走和生成表示向量两个部分,首先…...
微服务项目【服务调用分布式session共享】
nginx动静分离 第1步:通过SwitchHosts新增二级域名:images.zmall.com 第2步:将本次项目的所有静态资源js/css/images复制到nginx中的html目录下 第3步:在nginx的核心配置文件nginx.conf中新增二级域名images.zmall.com访问映射…...
神经网络的万能逼近定理
这是我见过的讨论神经网络万有逼近问题的最好的文章。在文章中,给出了最清晰,简洁的构造性证明。揭示了它的本质。 三十年前,我们接触到神经网络的万有逼近问题。发表了几篇文章。这些文章把神经网络能力的来历、优点、缺点,都已…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...
