当前位置: 首页 > news >正文

二叉树进阶

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析(3)

在这里插入图片描述


目录

  • 👉🏻二叉搜索树
    • 概念
  • 👉🏻二叉搜索树模拟实现
    • Insert插入
    • find查找
    • 中序遍历
    • Erase删除
    • InsertR递归插入
    • FindR递归查找
    • EraseR递归删除
  • 🍒BinarySearchTree.h

👉🏻二叉搜索树

概念

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

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

即:左<根<右

在这里插入图片描述

👉🏻二叉搜索树模拟实现

Insert插入

bool Insert(const K& key){if (_root == nullptr)//如果为空直接创建新结点{_root = new Node(key);return true;}Node* cur = _root;Node* parent = nullptr;while (cur)//key比当前cur结点的key值小往左边走,大则往右边走,直到遇到空{parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key);//此时遇到空要创建新结点//但此时我们还要记得将其与parent连接起来,至于是在parent的左边还是右边,看比大小if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}

过程即为:小于往左走,大于往右走,遇到空创建新结点,进行连接父节点

find查找

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;}elsereturn true;//相等说明找到,返回true}return false;}

中序遍历

void _InOrder(Node* root)//中序遍历{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void InOrder()//套一层{_InOrder(_root);cout << endl;}

Erase删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点

而a情况可以归属于b和c任意一个情况,a情况当把结点删除后,父节点想向指向左右哪边都行,反正都为空无所谓。

  • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
  • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
  • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点
    中,再来处理该结点的删除问题–替换法删除

替换法删除:
1.要么从左子树中找到最大结点来替换
2.要么从右子树找到最小结点来替换

所以现在梳理一下代码思路
1.先找到要删除的结点位置,能找到再删除,找不到返回false
2.开始删除,判情况(b,c,d),对症下药

代码如下

bool Erase(const K& key){Node* cur = _root;Node* parent = nullptr;while (cur)//寻找要删除的结点{	if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//找到了就可以开始删除了,但是要判情况,对症下药if (cur->_left == nullptr){//左边为空,则删除后,将父节点连接cur的右边if (cur == _root)//如果要删除的结点就是初始根结点{_root = cur->_right;}//先确定此时cur在父节点的左边还是右边if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}else if (cur->_right == nullptr){//右边为空if (cur == _root)//如果要删除的结点就是初始根结点{_root = cur->_left;}if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}else{//左右都不为空,此时用替换法//这里我们以寻找右边树最小值的替换法执行;而右边树最小值即可以认为就是右边树最左边结点Node* parent = cur;Node* subleft = cur->_right;while (subleft->_left)//当左边遇到空,说明此时subleft已经遍历到最左边{parent = subleft;subleft = subleft->_left;}//找到后,可以进行交换了swap(cur->_key, subleft->_key);//现在进行删除,而且删除情况属于a情况if (subleft == parent->_left){parent->_left = subleft->_right;//这边=subleft->_right或者subleft->_left都可以}else{parent->_right = subleft->_right;}}return true;}}return false;}

InsertR递归插入

bool _InsertR(Node*& root, const K& key)//递归插入{if (root == nullptr){root = new Node(key);//传引用的好处就是此时的root就是其父节点的左/右节点,无需记录父节点return true;}if (root->_key > key){_InsertR(root->_left, key);}else if (root->_key < key){_InsertR(root->_right, key);}elsereturn false;}

FindR递归查找

bool _FindR(Node* root, const K& key)//递归查找{if (root == nullptr)return false;if (root->_key > key){FindR(root->_left, key);}else if (root->_key < key){FindR(root->_right, key);}elsereturn true;}

EraseR递归删除

bool _EraseR(Node*& root, const K& key)//这里我们仍然用引用root,这样连接时就不用记录父节点了{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{//开始删除if (root->_left == nullptr){//左为空root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{//左右都不为空//这里以寻找右子树最小值Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);// 转换成在子树去递归删除return _EraseR(root->_right, key);}}}

🍒BinarySearchTree.h

#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};
template <class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:bool Insert(const K& key){if (_root == nullptr)//如果为空直接创建新结点{_root = new Node(key);return true;}Node* cur = _root;Node* parent = nullptr;while (cur)//key比当前cur结点的key值小往左边走,大则往右边走,直到遇到空{parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key);//此时遇到空要创建新结点//但此时我们还要记得将其与parent连接起来,至于是在parent的左边还是右边,看比大小if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}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;}elsereturn true;//相等说明找到,返回true}return false;}bool Erase(const K& key){Node* cur = _root;Node* parent = nullptr;while (cur)//寻找要删除的结点{	if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//找到了就可以开始删除了,但是要判情况,对症下药if (cur->_left == nullptr){//左边为空,则删除后,将父节点连接cur的右边if (cur == _root)//如果要删除的结点就是初始根结点{_root = cur->_right;}//先确定此时cur在父节点的左边还是右边if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}else if (cur->_right == nullptr){//右边为空if (cur == _root)//如果要删除的结点就是初始根结点{_root = cur->_left;}if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}else{//左右都不为空,此时用替换法//这里我们以寻找右边树最小值的替换法执行;而右边树最小值即可以认为就是右边树最左边结点Node* parent = cur;Node* subleft = cur->_right;while (subleft->_left)//当左边遇到空,说明此时subleft已经遍历到最左边{parent = subleft;subleft = subleft->_left;}//找到后,可以进行交换了swap(cur->_key, subleft->_key);//现在进行删除,而且删除情况属于a情况if (subleft == parent->_left){parent->_left = subleft->_right;//这边=subleft->_right或者subleft->_left都可以}else{parent->_right = subleft->_right;}}return true;}}return false;}void InOrder()//套一层{_InOrder(_root);cout << endl;}bool FindR(const K& key){return _FindR(_root, key);}bool InsertR(const K& key){return _InsertR(_root,key);}bool EraseR(const K& key){return _EraseR(_root, key);}
private:bool _EraseR(Node*& root, const K& key)//这里我们仍然用引用root,这样连接时就不用记录父节点了{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{//开始删除if (root->_left == nullptr){//左为空root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{//左右都不为空//这里以寻找右子树最小值Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);// 转换成在子树去递归删除return _EraseR(root->_right, key);//root->_right或者root->_left都可以,反正都是空}}}bool _InsertR(Node*& root, const K& key)//递归插入{if (root == nullptr){root = new Node(key);//传引用的好处就是此时的root就是其父节点的左/右节点,无需记录父节点return true;}if (root->_key > key){_InsertR(root->_left, key);}else if (root->_key < key){_InsertR(root->_right, key);}elsereturn false;}bool _FindR(Node* root, const K& key)//递归查找{if (root == nullptr)return false;if (root->_key > key){FindR(root->_left, key);}else if (root->_key < key){FindR(root->_right, key);}elsereturn true;}void _InOrder(Node* root)//中序遍历{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}Node* _root = nullptr;
};

如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
在这里插入图片描述
在这里插入图片描述

http://www.lryc.cn/news/203982.html

相关文章:

  • 前端性能优化 - 虚拟滚动
  • 手写 Promise(1)核心功能的实现
  • 深入探究Java内存模型
  • 深度学习 | Pytorch深度学习实践 (Chapter 10、11 CNN)
  • 谈谈你对spring boot 3.0的理解
  • 【大数据】Hadoop
  • Spring实例化源码解析之Bean的实例化(十二)
  • git常用的几条命令介绍
  • 使用VisualSVN在Windows系统上设置SVN服务器,并结合内网穿透实现公网访问
  • 第18章 SpringCloud生态(三)
  • leetcode:2347. 最好的扑克手牌(python3解法)
  • 2007-2022 年上市公司国内外专利授权情况数据
  • 安全渗透测试网络基础知识之路由技术
  • 【大数据】Kafka 实战教程(二)
  • React 框架
  • 数据结构与算法之图: Leetcode 133. 克隆图 (Typescript版)
  • illuminate/database 使用 一
  • 前端koa搭建服务器(保姆级教程)——part1
  • js逆向第一课 密码学介绍
  • Dynamic DataSource 多数据源配置【 Springboot + DataSource + MyBatis Plus + Druid】
  • MyBatis:配置文件
  • ARM,基础、寄存器
  • FC-TSGAS-1624 CP451-10 MVI56E-MNETC IC697CMM742
  • 异或运算.
  • NewStarCTF2023week4-逃(反序列化字符串逃逸)
  • PyTorch Tensor 形状
  • RabbitMQ运行机制和通讯过程介绍
  • UE4 TextRender显示中文方法
  • C++动态规划算法的应用:得到 K 个半回文串的最少修改次数 原理源码测试用例
  • Pyside6 QFileDialog