二叉树进阶——手撕二叉搜索树

troop主页:troop

手撕二叉搜索树

  • 1.二叉搜索树的定义
  • 2.实现(非递归)
    • 补充结构
    • 2.1查找
    • 2.2插入
    • 2.3删除(==重要==)
      • 情况1(无孩子&&一个孩子)
  • 3.二叉搜索树的应用
    • 3.1K模型
    • 3.2KV模型
      • 3.2.1KV模型的实现
  • 总结
  • 二叉搜索树源代码

1.二叉搜索树的定义

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上的所有节点的值都大于根节点的值

在这里插入图片描述

2.实现(非递归)

补充结构

//struct BinarySearchTreeNode
template<class K>
struct BSTreeNode
{typedef BSTreeNode<K> Node;Node* _left;Node* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};/class BinarySearchTree
template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:BSTree() = default;BSTree(const BSTree<K>& t){_root = copy(t._root);}Node* copy(Node* root){if (root == nullptr)return nullptr;Node* newroot = new Node(root->_val);newroot->_left = copy(root->_left);newroot->_right = copy(root->_right);return newroot;}~BSTree(){Destroy();}void Destroy(){return _Destroy(_root);}void _Destroy(Node* root){if (root == nullptr)return;_Destroy(root->_left);_Destroy(root->_right);delete root;}
private:Node* _root;
};

2.1查找

根据它的定义查找就是,跟节点比,比节点大就去它的右子树中寻找,比他小就去它的左子树中寻找

	bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return true;}}return false;}

2.2插入

在这里插入图片描述
插入也很简单,例如上图我们要插入16,我们就先找到要插入的位置,然后为了方便我们记录整个过程我们需要一个父节点。

	bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left=cur;}else{parent->_right=cur;}return true;}

现在可以进行测试代码的正确性。
在这里插入图片描述
注意,搜索二插入要有序它走的是中序遍历。

2.3删除(重要

删除比插入麻烦的多,我们删除值原则就是要保证它还是搜索二叉树,它的性质不可以改变。这就挺麻烦的,所以我们在删除这里用替换删除
替换删除:找到一个可以替换的节点,交换值,转换删除它。
可以替换的节点是:左子树的最大or右子树的最小。

下面我们来分析一下删除的各种情况

  1. 删除孩子节点
  2. 删除只有一个孩子的节点
  3. 删除两个孩子的节点
    这里总结下,情况1和2可以归为一类。情况3我们就要用到替换删除法

情况1(无孩子&&一个孩子)

在这里插入图片描述

//找到了开始删除//第一种if (cur->_left == nullptr)//我的左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left)//我是父亲的左{parent->_left = cur->_right;}else//我是父亲的左{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;return true;}

###情况二(两个孩子)
在这里插入图片描述
找到右子树的最小,把它的值复制给cur,就转换成了删除叶子节点

				else//第二种(俩孩子)替换删除法{Node* rightMinparent = cur;Node* rightMin = cur->_right;while (cur->_right){rightMinparent = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;if (rightMin == rightMinparent->_left){rightMinparent->_left = rightMin->_right;}else{rightMinparent->_right = rightMin->_right;}delete rightMin;return true;}

3.二叉搜索树的应用

3.1K模型

K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值。
比如:给一个单词word,判断该单词是否拼写正确。这个就是普通的二叉搜索树

3.2KV模型

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。
通过key值快速查找另外一个值在不在。我们用二叉搜索树这个用的是比较多的
生活中的KV模型例如:商场车库,进去都可以进入(记录车牌(key)进入时间(value))
出:付费出(通过车牌(key),查询进入的时间(value))。
还有字典查询,高铁身份证进站等等。

3.2.1KV模型的实现

这个就是多加了一个对象,实现直接CV上面的代码

namespace key_value
{template<class K, class V>struct BSTreeNode{typedef BSTreeNode<K, V> Node;Node* _left;Node* _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://插入bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return true;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}//Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}//中序遍历void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);std::cout << root->_val << " ";_InOrder(root->_right);}void InOrder(){_InOrder(_root);cout << endl;}//3.删除bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_val < key){parent = cur;cur = cur->_right;}else if (cur->_val > key){parent = cur;cur = cur->_left;}else{//找到了开始删除//第一种(无孩子&&一个孩子)if (cur->_left == nullptr)//我的左为空{if (cur == _root){_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else//我是父亲的右节点{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr)//我的右为空{if (cur == _root){_root = cur->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else//我是父亲的右节点{parent->_right = cur->_left;}}delete cur;return true;}else//第二种(有两个孩子)替换删除法{Node* rightMinparent = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinparent = rightMin;rightMin = rightMin->_left;}cur->_val = rightMin->_val;if (rightMin == rightMinparent->_left)rightMinparent->_left = rightMin->_right;elserightMinparent->_right = rightMin->_right;delete rightMin;return true;}}}return false;}//void InOrder()//{//	_InOrder(_root);//	cout << endl;//}//private://	void _InOrder(Node* root)//	{//		if (root == nullptr)//			return;//		_InOrder(root->_left);//		cout << root->_key << " ";//		_InOrder(root->_right);//	}private:Node* _root = nullptr;};
}

我们可以用哥=个例子来玩一玩这个KV模型

void TestBSTree()
{key_value::BSTree<string, string> dict;dict.Insert("insert", "插入");dict.Insert("erase", "删除");dict.Insert("left", "左边");dict.Insert("string", "字符串");string str;while (cin >> str){auto ret = dict.Find(str);if (ret){cout << str << ":" << ret->_value << endl;}else{cout << "单词拼写错误" << endl;}}
}

在这里插入图片描述

总结

总的来说二叉搜索树,比较难的地方就是删除部分,多画图多思考。
下篇我们就要深入二叉搜索树。

二叉搜索树源代码

#pragma once
#include<iostream>
using namespace std;
//struct BinarySearchTreeNode
template<class K>
struct BSTreeNode
{typedef BSTreeNode<K> Node;Node* _left;Node* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};//class BinarySearchTree
template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:BSTree() = default;BSTree(const BSTree<K>& t){_root = copy(t._root);}Node* copy(Node* root){if (root == nullptr)return nullptr;Node* newroot = new Node(root->_val);newroot->_left = copy(root->_left);newroot->_right = copy(root->_right);return newroot;}~BSTree(){Destroy();}void Destroy(){return _Destroy(_root);}void _Destroy(Node* root){if (root == nullptr)return;_Destroy(root->_left);_Destroy(root->_right);delete root;}bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return true;}}return false;}bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left=cur;}else{parent->_right=cur;}return true;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{//找到了开始删除//第一种if (cur->_left == nullptr)//我的左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left)//我是父亲的左{parent->_left = cur->_right;}else//我是父亲的左{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;return true;}else//第二种(俩孩子)替换删除法{Node* rightMinparent = cur;Node* rightMin = cur->_right;while (cur->_right){rightMinparent = rightMin;rightMin = rightMin->_left;}if (rightMinparent->_left == rightMin){rightMinparent->_left = rightMin->_right;}else{rightMinparent->_right = rightMin->_right;}}}}return false;}void Inorder(){_Inorder(_root);cout << endl;}
private:void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_key << " ";_Inorder(root->_right);}
private:Node* _root=nullptr;
};

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

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

相关文章

Github 2024-04-05Java开源项目日报Top9

根据Github Trendings的统计,今日(2024-04-05统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9TypeScript项目1OpenAPI 生成器:基于规范自动生成API工具 创建周期:2155 天开发语言:Java协议类型:Apache License 2.0Star数量:1…

linux操作系统安装及命令初识,上岸蚂蚁金服

310 包&#xff09; desktop 1800个包左右 内容必须大于 768M 系统设置 分区设置 挂载点 /boot / swap 交换分区–占用磁盘容量 网络配置 网卡配置 设置为ON 主机名配置 Begin installation 设置 root 用户密码 命令初识 命令 选项 参数&#xff1a; 命令选项参数…

独角数卡对接码支付收款教程

1、到码支付后台找到支付配置。2、将上面的复制依次填入&#xff0c;具体看下图&#xff0c;随后点立即添加 商户ID商户PID 商户KEY异步不能为空 商户密钥商户密钥

【Python使用】嘿马头条完整开发md笔记第4篇:数据库,1 方案选择【附代码文档】

嘿马头条项目从到完整开发笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;课程简介&#xff0c;ToutiaoWeb虚拟机使用说明1 产品介绍,2 原型图与UI图,3 技术架构,4 开发,1 需求,2 注意事项。数据库&#xff0c;理解ORM1 简介,2 安装,3 数据库连接…

六、从零实战企业级K8S本地部署ThingsBoard专业版集群

1、从 docker hub 拉取 ThingsBoard PE 映像(所有节点) 1.1、查看k8s信息(主节点) kubectl cluster-info #查看k8s集群信息 kubectl get node #查看节点信息 kubectl get pod -A #查看内部组件1.2、从 docker hub 拉取 ThingsBoard PE 映像(所有…

《QT实用小工具·十六》IP地址输入框控件

1、概述 源码放在文章末尾 该项目为IP地址输入框控件&#xff0c;主要包含如下功能&#xff1a; 可设置IP地址&#xff0c;自动填入框。 可清空IP地址。 支持按下小圆点自动切换。 支持退格键自动切换。 支持IP地址过滤。 可设置背景色、边框颜色、边框圆角角度。 下面…

【35分钟掌握金融风控策略5】风控策略开发1

目录 风控策略开发 策略类型划分 单维度策略开发 风控策略开发 在风控过程中&#xff0c;风控策略最终是要直接参与风控决策的&#xff0c;风控策略的好坏会对风控结果产生直接影响&#xff0c;因此&#xff0c;开发有效的风控策略至关重要。 策略类型划分 在实际生产中&…

Redis Desktop Manager可视化工具

可视化工具 Redis https://www.alipan.com/s/uHSbg14XmsL 提取码: 38cl 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 官网下载&#xff08;不推荐&#xff09;&#xff1a;http…

selenium 遮罩层

之前写智联自动投简历 和boss自动投简历的时候 发现操作到上限之后就有个遮罩层&#xff0c;会在当前页面有个顶层得div 没办法获取下面的内容 # 假设遮罩层元素有一个特定的ID或者其他属性 没有id xpath 或者class 都可以mask_element WebDriverWait(driver, 10).until(EC.…

网络网络层之(3)IPv6地址

网络网络层之(3)IPv6协议 Author: Once Day Date: 2024年4月2日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

C语言-------内存函数

前面向大家介绍了C语言中的字符函数和字符串函数&#xff0c;今天再向大家介绍一下类似的函数———— C语言中的内存函数。 1. memcpy函数的使用和模拟实现 memcoy函数是一种通过内存来复制内容的一种函数&#xff0c;以字节为基本单位进行&#xff0c;斌并且是一个可以复制…

git可视化工具

Gitkraken GitKraken 是一款专门用于管理和协作Git仓库的图形化界面工具。它拥有友好直观的界面&#xff0c;使得Git的操作变得更加简单易用&#xff0c;尤其适合那些不熟悉Git命令行的开发者。GitKraken提供了丰富的功能&#xff0c;如代码审查、分支管理、仓库克隆、提交、推…

如何使用CSS构建一个瀑布流布局

如何使用CSS构建一个瀑布流布局 瀑布流布局是一种常见的网页布局方式&#xff0c;其中元素以不同的大小排列&#xff0c;且行与列之间没有不均匀的间隙。在瀑布流布局中&#xff0c;即使某一行或列中的元素较短&#xff0c;下一个元素也会占据空间。 如何实现瀑布流布局 实现…

java框架学习——反射概述及简易版框架搭建

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup!!! 反射 反射&#xff08;Reflection&#xff09;&#xff1a;加载类&#xff0c;并允许以编程的方式解剖类中的各种成分&#xff08;成员变量&#xff0c;方法&#xff0c;构造器等&#xff09; 1&…

C++之类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1访问限定符 4.2 类的两种定义方式 第一种&#xff1a; 第二种&#xff1a; 4.3封装 5.类的实例化 6.类对象模型 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;…

出门一笑, “栈” 落江横 (Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

03-自媒体文章发布

自媒体文章发布 1)自媒体前后端搭建 1.1)后台搭建 ①&#xff1a;资料中找到heima-leadnews-wemedia.zip解压 拷贝到heima-leadnews-service工程下&#xff0c;并指定子模块 执行leadnews-wemedia.sql脚本 添加对应的nacos配置 spring:datasource:driver-class-name: com…

23年蓝桥杯省赛 动态规划DP

动态规划 就是:给定一个问题&#xff0c;我们把它拆成一个个子问题&#xff0c;直到子问可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重量计算&#xff0c;再根据子问题答察反推&#xff0c;得出问解的一种方法。 题目&#xff1a; 这天&#xff0c;一只蜗牛…

QT串口接收数据并进行波形显示(含源码)

**使用QT在串口调试助手基础上实现波形显示&#xff08;含源码&#xff09; 评论比较多留言需要源码的&#xff0c;逐个发邮箱比较麻烦也不能及时回复&#xff0c;现将源码上传至链接&#xff08;无需积分下载&#xff09;https://download.csdn.net/download/m0_51294753/877…

cJSON(API的详细使用教程)

我们今天来学习一般嵌入式的必备库&#xff0c;JSON库 1&#xff0c;json和cJSON 那什么是JSON什么是cJSON&#xff0c;他们之间有什么样的关联呢&#xff0c;让我们一起来探究一下吧。 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&…