搜索二叉树的概念及实现

搜索二叉树的概念

搜索二叉树规则(左小右大): 

  1. 非空子树的键值小于其根节点的键值
  2. 非空子树的键值大于其根节点的键值
  3. 左右子树均为搜索二叉树

 如图:

 在搜索时,若大于根,则去右子树寻找;若小于根,则去左子树寻找。直到找到或为空结束。在理想状态下只需查找树的高度次。

代码实现

#pragma once
#include<iostream>
using namespace std;//key版本
namespace key
{template<class T>struct BSTreeNode{BSTreeNode<T>* _left;BSTreeNode<T>* _right;T _key;BSTreeNode(const T& key):_left(nullptr),_right(nullptr),_key(key){}};template<class T>class BSTree{typedef BSTreeNode<T> Node;public:bool Insert(const T& 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->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else{parent->_right = cur;}return true;}Node* find(const T& key){Node* cur = root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return cur;}}return nullptr;}bool Erase(const T& key){Node* parent = nullptr;Node* cur = root;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){if (cur == root){root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}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;}else{Node* rightMinParent = cur;Node* rightMin = cur -> _right;while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}swap(cur->_key, rightMin->_key);//假设没有进循环,那么rightMin = cur->_right,所以要判断一下。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);}Node* root = nullptr;};
}//key_value版本
namespace key_value
{template<class T, class V>struct BSTreeNode{BSTreeNode<T,V>* _left;BSTreeNode<T,V>* _right;T _key;V _value;BSTreeNode(const T& key,const V& value = V()):_left(nullptr), _right(nullptr), _key(key),_value(value){}};template<class T, class V>class BSTree{typedef BSTreeNode<T,V> Node;public:bool Insert(const T& 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->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key, value);;if (parent->_key > key){parent->_left = cur;}else{parent->_right = cur;}return true;}Node* find(const T& key){Node* cur = root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return cur;}}return nullptr;}bool Erase(const T& key){Node* parent = nullptr;Node* cur = root;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){if (cur == root){root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}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;}else{Node* rightMinParent = cur;Node* rightMin = cur->_right;//找cur右子树最小的值while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}swap(cur->_key, rightMin->_key);swap(cur->_value, rightMin->_value);//假设没有进循环,那么rightMin = cur->_right,所以要判断一下。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 << " " << root->_value << endl;_InOrder(root->_right);}Node* root = nullptr;};}

Insert函数详解

bool Insert(const T& 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->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else//等于{//出现重复,不插入return false;}}//将新节点连接入树cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else{parent->_right = cur;}return true;}

(1)若根节点为空,为其新建(new)一个节点。

(2)若根节点不为空,则根据二叉树定义(大于当前根的键值进右子树,小于当前根的键值进左子树)去寻找合适的位置新建节点。出现等于即重复的情况不插入。

(3)新节点连接入树时,要检查他是parent的左节点还是右节点,判断完毕后再连接。

 Erase函数详解

bool Erase(const T& key){Node* parent = nullptr;Node* cur = root;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){if (cur == root){root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}//假设目标右子树为空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;}else//左右子树都不为空{Node* rightMinParent = cur;Node* rightMin = cur -> _right;while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}swap(cur->_key, rightMin->_key);//假设没有进循环,那么rightMin = cur->_right,所以要判断一下。if (rightMin == rightMinParent->_left)rightMinParent->_left = rightMin->_right;elserightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;}

(1)第一步寻找删除目标(有可能是根节点),找不到返回false,表示删除失败。

(2)删除

  1. 目标左子树为空
  2. 目标右子树为空
  3. 目标左右子树都不为空

左子树为空

删除目标不是根节点时,让目标的父节点指向他的右子树。当然也要判断目标是他的父节点的左子树还是右子树。

为父节点的左子树:

 

 为父节点的右子树:

 目标为根节点:

 

 (右子树为空的情况只是与左子树为空方向相反,不过多赘述)

左右子树都不为空时

交换    目标的键值   和   目标的右子树中的最左节点的键值    ,然后让最左节点的父节点指向最左节点的右子树(因为是最左节点,所以左子树一定为空,右子树可能为空可能不为空),最后将这个最左节点删除。

 让最左节点的父节点指向最左节点的右子树前,也要判断该最左节点是否是其父节点的左子树,因为有可能出现图中的情况。

此时右子树最左节点是7,但他却是父节点的右子树。此时是父节点的右指向最左节点的右子树,而不是父节点的左去指向。

原理

删除后要保持树还是搜索二叉树。那么首先先理清一下节点键值的关系。

 所以我们是希望保持如图的节点关系,那么右子树的最左节点满足做根节点条件。

因为在任意树中都有    右大于根大于左    ,所以该树最左节点存储最小键值。

特殊存储情况 

当出现顺序插入时,会呈现出这样的情况,这个时候遍历的时间复杂度就退化到了O(n),此时搜索二叉树就失去了意义。不过平衡二叉树和红黑树解决了高度不平衡导致搜索效率下降的问题。

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

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

相关文章

Python:基础爬虫

Python爬虫学习&#xff08;网络爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字…

flask实现抽奖程序(一)

后端代码E:\LearningProject\lottery\app.py from flask import Flask, render_template import randomapp Flask(__name__)employees [赵一, 钱二, 孙三, 李四, 周五, 吴六, 郑七, 王八]app.route(/) def hello_world():return render_template(index.html, employeesemplo…

企业多云策略的优势与实施指南

企业在选择云服务提供商时&#xff0c;常见的选项包括亚马逊AWS、微软Azure、谷歌云GCP、阿里云、腾讯云和华为云。为了避免过度依赖单一供应商&#xff0c;许多企业选择采用多云策略&#xff0c;这样可以充分利用不同云服务的优势&#xff0c;同时避免重复工作和其他额外的工作…

每天五分钟计算机视觉:如何在现有经典的卷积神经网络上进行微调

本文重点 在深度学习领域,卷积神经网络(Convolutional Neural Networks,CNN)因其强大的特征提取和分类能力而广泛应用于图像识别、自然语言处理等多个领域。然而,从头开始训练一个CNN模型往往需要大量的数据和计算资源,且训练时间较长。幸运的是,迁移学习(Transfer Le…

git如果将多次提交压缩成一次

将N个提交压缩到单个提交中有两种方式&#xff1a; git reset git reset的本意是版本回退&#xff0c;回退时可以选择保留commit提交。我们基于git reset的作用&#xff0c;结合新建分支&#xff0c;可以实现多次commit提交的合并。这个不需要vim编辑&#xff0c;很少有冲突。…

WEB基础--TOMCAT服务器

服务器概述 什么是服务器 服务器&#xff1a;就是一个提供为人民服务的机器&#xff0c;这里的服务器主要指计算机服务器&#xff0c;分为两种&#xff1a;服务器软件和硬件服务器&#xff1b; 服务器分类 1、硬件服务器&#xff1a;安装了服务器软件的主机。就相当于高配的…

复合机器人以其高度的灵活性和操作效率,展现了显著的优势

随着工业4.0的深入推进和智能制造的快速发展&#xff0c;复合机器人作为一种集成移动机器人和工业机器人功能的先进设备&#xff0c;正逐步成为工业自动化领域的新宠。特别是在磁钢上下料的应用中&#xff0c;复合机器人以其高度的灵活性和操作效率&#xff0c;展现了显著的优势…

基于C#开发web网页管理系统模板流程-主界面密码维护功能完善

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面统计功能完善-CSDN博客 一个合格的管理系统&#xff0c;至少一定存在一个功能——用户能够自己修改密码&#xff0c;理论上来说密码只能有用…

Matlab图像处理——细胞图像的分割和计数显示

一. 项目介绍 使用MATLAB编写的细胞图像分割及计数系统&#xff0c;实现了对图像内细胞的计数&#xff0c;以及对每个细胞周长和面积的测量&#xff0c;并分别展示了分割后的每个细胞的图像。实验步骤共分为图像预处理、图像预分割、空洞填充、黏连细胞分割、细胞个数统计、细胞…

TikTok网红营销指南 | 怎么找到TikTok网红并进行合作?

如果你打算在tiktok上进行营销&#xff0c;忽略与tiktok网红合作无异于错失良机&#xff0c;时尚博主Sophia仅用一条30秒的视频展示了自己从一家新兴品牌购买的连衣裙&#xff0c;视频迅速获得了数百万的点赞和评论&#xff0c;也让该品牌的销量翻了好几倍。 这种与网红合作的策…

Qt绘图项目 - 简易表盘

废话少说&#xff0c;放码过来 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();prot…

LayUI使用(二)处理表格会出现下拉框的问题

一、问题描述 如下&#xff0c;layui的表格渲染后&#xff0c;当鼠标悬停在表格项时会出现右侧的下拉框&#xff0c;layui版本较老&#xff0c;原因未知 二、处理办法 在cols里面加上width&#xff0c;也不用每个都加&#xff0c;加一部分表格项即可 注意&#xff1a;若想禁止…

iOS/iPadOS18Beta是否值得升级体验?Bug汇总和升级办法分享!

苹果昨天发布了iOS/iPadOS18Beta更新&#xff0c;引入了诸多新功能/新特性&#xff0c;很多喜欢尝鲜的用户已经在第一时间进行了升级。 iOS/iPadOS18Beta目前存在不少Bug&#xff0c;建议暂时不要更新&#xff0c;轻则浪费装机时间&#xff0c;重则丢失相关数据&#xff0c;甚至…

ping: www.baidu.com: 未知的名称或服务(IP号不匹配)

我用的是VMware上的Red Hat Enterprise Linux 9&#xff0c;出现了能联网但ping不通外网的情况。 问题描述&#xff1a;设置中显示正常连接&#xff0c;而且虚拟机右上角有联网的图标&#xff0c;但不能通外网。 按照网上教程修改了/etc/resolv.conf和/etc/sysconfig/network-…

江协科技51单片机学习-1 安装Keil5开发环境

前言&#xff1a; 本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记&#xff0c;在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。 引用&#xff1a; 51单片机入门教程-2…

Flask基础2-Jinja2模板

目录 1.介绍 2.模板传参 1.变量传参 2.表达式 3.控制语句 4.过滤器 5.自定义过滤器 6.测试器 7.块和继承 flask基础1 1.介绍 Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作 者。他的设计思想来源于Django的模…

Shell脚本从入门到实战

一、概述 shell 是一个命令行解释器&#xff0c;它接受应用程序、用户命令&#xff0c;然后调用操作系统内核。 shell 还是一个功能强大编程语言&#xff0c;易调试&#xff0c;易编写&#xff0c;灵活性强。 二、mac 怎么重启docker 1.如何重启 Docker on Mac 在 macOS 上…

Python界面编辑器Tkinter布局助手 使用体验

一、发现 我今天在网上搜关于Python Tkinter方面的信息时&#xff0c;发现了Python界面编辑器 Tkinter布局助手 的使用说明。 https://blog.csdn.net/weixin_52777652/article/details/135291731?spm1001.2014.3001.5506 这个编辑器是个开源的项目&#xff0c;个人用户可以…

随手记:商品信息过多,展开收起功能

UI原型图&#xff1a; 页面思路&#xff1a; 在商品信息最小item外面有一个包裹所有item的标签&#xff0c;控制这个标签的高度来实现展开收起功能 <!-- 药品信息 --><view class"drugs" v-if"inquiryInfoSubmitBtn"><view class"…

C++ 14 之 宏函数

c14宏函数.cpp #include <iostream> using namespace std;// #define PI 3.14 // 宏函数 // 宏函数缺陷1: 必须用括号保证运算的完整性 #define MY_ADD(x,y) ((x)(y))// 宏函数缺陷2&#xff1a;即使加了括号&#xff0c;有些运算依然与预期不符 #define MY_COM(a,b) ((…