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

搜索二叉树 Binary Search Tree(BST)

【提醒】本章内容需掌握二叉树结构的基本概念和特性,不然可能阅读起来比较费劲。

一、 概念

        什么是搜索二叉树?搜索二叉树和普通二叉树的却别是什么?

       答: 二叉搜索树又称二叉排序树,它或者是一棵空树

或者是具有以下性质的二叉树:

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

 搜索二叉树 最重要的特性之一:搜索二叉树 中序遍历可以得到一个有序的序列

把文字转换成图形:下面是一颗搜索二叉树

 

下面再来看两个例子更深刻地理解什么是搜索二叉树:

 二、搜索二叉树的增删查改

1. 搜索二叉树插入节点(增)

搜索二叉树的插入分为三个步骤

  1. 从根节点开始。

  2. 如果插入的值小于当前节点,移动到左子节点;如果大于,移动到右子节点。

  3. 重复步骤2,直到找到一个空位置插入新值。

 以下用一个插入建树的详细图解说明:

以数值{8 ,3 ,1 ,10 ,1}为例:

【注意】:二叉搜索树中,如果插入的值已经存在,处理方式可以有几种,现阶段采用第一种:

  1. 忽略重复值:简单地不插入重复值,保留原有节点。

  2. 计数重复值:在每个节点中增加一个计数器,如果插入相同值则增加计数器,而不是新建节点。

  3. 允许重复值:按某种规则插入,如将相同值插入到右子树。


2. 搜索二叉树节点的删除

        搜索二叉树阶段的删除相较于插入是要复杂一点的,需要分情况讨论。

节点的删除:

        首先查找元素是否在二叉搜索树中,如果不存在,则返回 false

元素存在的情况,则分以下四种情况分别处理(假设要删除的结点为 N):

  1. 要删除的结点 N 左右孩子均为空。

  2. 要删除的结点 N 左孩子为空,右孩子结点不为空。

  3. 要删除的结点 N 右孩子为空,左孩子结点不为空。

  4. 要删除的结点 N 左右孩子结点均不为空。

 结合图形举例说明删除节点时会遇到的4种情况:

 

 

为了解决以上4种情况,分别对应4种解决方案:

1.左右孩子均为空

  • 把 N 结点的父节点对应孩子指针指向空,直接删除 N 结点(情况 1 可以当成 2 或者 3 处理,效果是一样的)。

2.左孩子为空,右孩子不为空

  • 把 N 结点的父节点对应孩子指针指向 N 的右孩子,直接删除 N 结点。

3.右孩子为空,左孩子不为空

  • 把 N 结点的父节点对应孩子指针指向 N 的左孩子,直接删除 N 结点。

4.左右孩子结点均不为空

  • 无法直接删除 N 结点,因为 N 的两个孩子无处安放,只能用替换法删除。

  • 找 N 左子树的值最大结点 R(最右结点)或者 N 右子树的值最小结点 R(最左结点)替代 N

  • 因为这两个结点中任意一个,放到 N 的位置,都满足二叉搜索树的规则。

  • 替代 N 的意思就是 N 和 R 两个结点的值交换,转而变成删除 R 结点,R 结点符合情况 2 或情况 3,可以直接删除。

 同样结合图形可以更好的理解4总处理方式:

 

 

 3. 搜索二叉树节点的查找

        搜索二叉树的查找逻辑很简单,其实在上面插入节点,已经使用过:

查找步骤:

  1. 从根节点开始

  2. 比较值:如果查找的值小于当前节点,移动到左子节点;如果大于,移动到右子节点。

  3. 找到值:重复步骤2,直到找到值或访问到空节点。

 4. 搜索二叉树节点的更改

       搜索二叉树节点的修改,如果直接修改可能会破坏BST的结构,使树不再满足搜索树的性质。

        所以在BST节点的修改,应该遵循以下步骤;

修改:

  1. 删除原节点:首先,删除需要修改的节点。

  2. 插入新值:然后,插入修改后的新值。

三、搜索二叉树的模拟实现

下面是搜索二叉树的模拟实现:(出自鄙人,如有错误愿联系指正)【仅参考非源码】

// BST.h#include <iostream>
#include <string>
using namespace std;namespace key
{template<class K>class BSTreeNode {public:BSTreeNode<K>* _leftNode;BSTreeNode<K>* _rightNode;K _key;BSTreeNode(const K& key):_key(key), _leftNode(nullptr), _rightNode(nullptr) {}};template<class K>class BinarySearchTree{typedef BSTreeNode<K> Node;public:BinarySearchTree() :_root(nullptr){}~BinarySearchTree(){Destroy(_root);}BinarySearchTree(const BinarySearchTree<K>& tree) {_root = Copy(tree._root);}BinarySearchTree<K>& operator=(BinarySearchTree<K> tree) {swap(_root, tree._root);return *this;}//节点插入bool Insert(const K& key){if (_root == nullptr) {_root = new Node(key);return true;}Node* parent = nullptr;Node* current = _root;while (current){if (current->_key < key) {parent = current;current = current->_rightNode;}else if (current->_key > key) {parent = current;current = current->_leftNode;}else { //搜索二叉树不允许值相等return false;}}if (parent->_key > key) {parent->_leftNode = new Node(key);return true;}else if (parent->_key < key) {parent->_rightNode = new Node(key);return true;}return false;}//查找(循环版)Node* Find(const K& key){Node* curr = _root;while (curr) {if (curr->_key < key) {curr = curr->_rightNode;}else if (curr->_key > key) {curr->_leftNode;}else {return curr;}}return nullptr;}bool Erase(const K& key) {Node* parent = nullptr;Node* curr = _root;while (curr) {if (curr->_key < key){parent = curr;curr = curr->_rightNode;}else if (curr->_key > key){parent = curr;curr = curr->_leftNode;}else {//等于情况下就删除 找到了if (curr->_leftNode == nullptr) {if (curr == _root) {//如果根就是要删除的节点_root = curr->_rightNode;}else {//判断现在找到的节点 是父的左还是右if (parent->_leftNode == curr) {parent->_leftNode = curr->_rightNode;}else {parent->_rightNode = curr->_rightNode;}}}else if (curr->_rightNode == nullptr) {if (curr == _root) {//如果根就是要删除的节点_root = curr->_leftNode;}else {//判断现在找到的节点 是父的左还是右if (parent->_leftNode == curr) {parent->_leftNode = curr->_leftNode;}else {parent->_rightNode = curr->_leftNode;}}}else { //两边都有Node* leftNodeParent = curr;Node* leftMaxNode = curr->_leftNode;//找左边树最大的节点代替while (leftMaxNode->_rightNode) {leftNodeParent = leftMaxNode;leftMaxNode = leftMaxNode->_rightNode;}// 交换要删除节点和左子树最大节点的键值curr->_key = leftMaxNode->_key;// 更新父节点指针,删除左子树的最大节点if (leftNodeParent->_leftNode == leftMaxNode) {leftNodeParent->_leftNode = leftMaxNode->_leftNode;}else {leftNodeParent->_rightNode = leftMaxNode->_leftNode;}curr = leftMaxNode;}delete curr;return true;}}return false;}//查找(递归版)bool FindR(const K& key){_FindR(_root, key);}//插入节点(递归版)bool InsertR(const K& key) {return _InsertR(_root, key); }//删除节点(递归版)bool EraseR(const K& key) {return _EraseR(_root, key);}//中序遍历打印void InOrder() {_InOrder(_root);}private://递归寻找子函数bool _FindR(Node* root, const K& key) {if (root == nullptr)return false;if (root->_key > key) {return _FindR(root->_leftNode, key);}else if (root->_key < key) {return _FindR(root->_rightNode, key);}else {return true;}}//递归删除子函数bool _EraseR(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key > key) {return _EraseR(root->_leftNode, key);}else if (root->_key < key) {return _EraseR(root->_rightNode, key);}else {//找到了删除Node* deleteNode = root;if (root->_leftNode == nullptr) {root = root->_rightNode;}else if (root->_rightNode == nullptr) {root = root->_leftNode;}else {//左右都有Node* leftMax = root->_leftNode;while (leftMax->_rightNode) {leftMax = leftMax->_rightNode;}swap(root->_key, leftMax->_key);return _EraseR(root->_leftNode, key);}delete deleteNode;return true;}}//递归插入子函数bool _InsertR(Node*& root, const K& key){if (root == nullptr) {root = new Node(key);return true;}if (root->_key > key) {return _InsertR(root->_leftNode, key);}else if (root->_key < key) {return _InsertR(root->_rightNode, key);}else {return false; //相同的返回false}}//中序遍历打印子函数void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_leftNode);cout << root->_key << " ";_InOrder(root->_rightNode);}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_leftNode);Destroy(root->_rightNode);delete root;root = nullptr;}Node* Copy(const Node* root){if (root == nullptr)return nullptr;Node* copyRoot = new Node(root->_key);copyRoot->_leftNode = Copy(root->_leftNode);copyRoot->_rightNode = Copy(root->_rightNode);return copyRoot;}Node* _root = nullptr;};void TestBSTree1();
}
//main.h
#include "binarysearchtree.h"
#include <iostream>namespace key {void TestBSTree1(){int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };BinarySearchTree<int> t;for (auto e : a){t.InsertR(e);}t.InOrder();cout << endl;t.Erase(4);t.InOrder();cout << endl;t.EraseR(6);t.InOrder();cout << endl;t.EraseR(7);t.InOrder();cout << endl;t.EraseR(3);t.InOrder();cout << endl;for (auto e : a){t.EraseR(e);}t.InOrder();}
}int main() 
{key::TestBSTree1();return 0;
}

程序运行结果:

1 3 4 6 7 8 10 13 14
1 3 6 7 8 10 13 14
1 3 7 8 10 13 14
1 3 8 10 13 14
1 8 10 13 14

 

 

相关文章:

搜索二叉树 Binary Search Tree(BST)

【提醒】本章内容需掌握二叉树结构的基本概念和特性&#xff0c;不然可能阅读起来比较费劲。 一、 概念 什么是搜索二叉树&#xff1f;搜索二叉树和普通二叉树的却别是什么&#xff1f; 答&#xff1a; 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树 或者是具有以下性…...

数据库表字段插入bug

瀚高数据库 目录 环境 BUG/漏洞编码 症状 触发条件 解决方案 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5.1 BUG/漏洞编码 3355 症状 数据库安全版v4.5.1&#xff0c;安装包为&#xff1a;hgdb4.5.1-see-centos7-x86-64-20210804.…...

信创环境模拟:X86架构下部署搭建aarch64的ARM虚拟机

在真实系统为x86架构下&#xff0c;搭建arm64的虚拟开发环境。在该环境中直接下载打包项目依赖的python运行环境。 前言 随着国家信创环境的要求普及&#xff0c;基本和国家沾边的政企事业单位都换成了信创环境&#xff0c;即ARM64的cpu服务器&#xff0c;而且该类服务器是不…...

TSO的资料

TSO即TCP Segmentation Offload&#xff0c;相关资料如下&#xff1a; Segmentation Offloads in the Linux Networking StackWhat is TCP Segmentation OffloadUnderstanding TCP Segmentation Offload (TSO) and Large Receive Offload (LRO) in a VMware environment...

OpenCV视觉分析之目标跟踪(3)实现基于金字塔的 Lucas-Kanade 算法来进行稀疏光流计算的类SparsePyrLKOpticalFlow的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 用于计算稀疏光流的类。 该类可以使用带有金字塔的迭代 Lucas-Kanade 方法来计算稀疏特征集的光流 cv::SparsePyrLKOpticalFlow 类是 OpenCV 库…...

乐维网管平台(一):如何精准掌控 IP 管理

业网络已成为支撑业务运转的关键基础设施&#xff0c;而在企业网络管理中&#xff0c;IP 管理至关重要&#xff0c;它就像是网络秩序的守护者&#xff0c;确保网络的高效运行、安全可靠。 一、为什么企业要进行 IP 管理 1. 优化资源分配 IP 地址作为网络中的重要资源&#xf…...

React-Route新版本(v6或以上)用法示例

新版本的React-Route (v6或以上&#xff0c;但不排序后续版本还会有修改)&#xff0c;移除了Switch&#xff0c;写法和老版本有一些区别&#xff0c;下面分享一个示例&#xff1a; JSX文件: import React, {StrictMode } from react import { createRoot } from react-dom/cli…...

卡方检验方法概述与类型——四格表和R*C表卡方检验案例

卡方检验是以卡方分布为基础&#xff0c;针对定类数据资料的常用假设检验方法。其理论思想是判断实际观测到的频数与有关总体的理论频数是否一致。 卡方统计量是实际频数与理论频数吻合程度的指标。卡方值越小&#xff0c;表明实际观察频数与理论频数越接近&#xff0c;反之卡…...

在浏览器和Node.js环境中使用Puppeteer的Rollup与Webpack打包指南

Puppeteer是一个Node.js库&#xff0c;它提供了一套高级API来通过DevTools协议控制Chrome或Chromium。虽然Puppeteer通常在服务器端使用&#xff0c;但有时你可能需要在浏览器环境中使用它的某些功能。本文将介绍如何使用Rollup和Webpack来打包包含Puppeteer或其轻量级版本Pupp…...

GPT论文整理提示词

论文阅读 指令1:粗读论文 请你阅读并理解这篇文献&#xff0c;然后将该篇文章的标题作为一级标题&#xff0c;将摘要和各个大标题作为二级标题&#xff0c;将小标题作为三级标题&#xff0c;将小标题下每一部分内容作为四级标题&#xff0c;给我以markdown的语言输出中文的翻…...

在培训班学网络安全有用吗

在当今数字化时代&#xff0c;网络安全问题日益凸显&#xff0c;成为了企业和个人关注的焦点。随着对网络安全人才需求的不断增长&#xff0c;各种网络安全培训班也如雨后春笋般涌现。然而&#xff0c;在培训班学网络安全真的有用吗? 一、网络安全的重要性与挑战 1. 信息时代的…...

Flink CDC系列之:理解学习YARN模式

Flink CDC系列之&#xff1a;理解学习YARN模式 准备会话模式在 YARN 上启动 Flink 会话设置 Flink CDC提交 Flink CDC Job Apache Hadoop YARN 是许多数据处理框架中流行的资源提供者。Flink 服务提交给 YARN 的 ResourceManager&#xff0c;后者在由 YARN NodeManagers 管理的…...

langgraph入门

使用langgraph框架搭建一个简易agent。 最近想学习一下agent相关知识&#xff0c;langgraph似乎挺好的&#xff0c;于是就来试一试。langgraph。看了官网&#xff0c;起核心思想是将agent中的角色和工具都当作是图的Node&#xff0c;整个agent流程通过增加Node之间的边来设定。…...

【Python】爬虫程序打包成exe

上一篇写了爬虫获取汽车之家配置表&#xff0c;师父要更方便使用甚至推广&#xff08;&#xff1f;&#xff09;&#xff0c;反正就是他们没有环境也能用嘛&#xff0c;我就直接打包了&#xff0c;界面不会做也懒得学了、、 1、下载pyinstaller&#xff08;清华镜像&#xff09…...

【力扣专题栏】两两交换链表中的节点,如何实现链表中两两相邻节点的交换?

这里写目录标题 1、题目描述解释2、算法原理解析3、代码编写 1、题目描述解释 2、算法原理解析 3、代码编写 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int…...

埋点采集的日志数据常见的格式简介

埋点采集的日志数据通常以结构化或半结构化的格式进行记录&#xff0c;以便于分析和处理。常见的格式包括&#xff1a; 1. JSON&#xff08;JavaScript Object Notation&#xff09; 特点&#xff1a;JSON 格式是一种轻量级的数据交换格式&#xff0c;具有良好的可读性和兼容…...

基于SSM高考志愿辅助填报系统设计与实现

前言 近年来&#xff0c;由于计算机技术和互联网技术的飞速发展&#xff0c;所以各企事业单位内部的发展趋势是数字化、信息化、无纸化&#xff0c;随着这一趋势&#xff0c;而各种决策系统、辅助系统也就应运而生了&#xff0c;其中&#xff0c;信息管理系统是其中重要的组成…...

elasticsearch 8.x 插件安装(六)之Hanlp插件

elasticsearch 8.x 插件安装&#xff08;六&#xff09;之Hanlp插件 elasticsearch插件安装合集 elasticsearch插件安装&#xff08;一&#xff09;之ik分词器安装&#xff08;含MySQL更新&#xff09; elasticsearch 8.x插件&#xff08;二&#xff09;之同义词安装如何解决…...

排序算法简记

列举几种基本的排序算法和排序思想 排序就是将一组对象按照某种逻辑顺序重新排列的过程。 一、选择排序 1、基本原理 最基本的排序&#xff0c;每次都从原有数据中选择最小或最大的数组放入新数据集中 2、步骤(以从小到大为例) 首先&#xff0c; 找到数组中最小的那个元素…...

Stable diffusion inference 多卡并行

stable diffusion 推理过程 多卡并行 注意事项 以SDXL为例&#xff0c;指定GPU&#xff0c;添加device_map参数信息 device_map {add_embedding: 1,decoder: 1,encoder: 1,conv_in: 1,conv_out: 1,post_quant_conv: 1,text_model: 6,conv_norm_out: 1,quant_conv: 1,time_em…...

KITTI数据集实战指南:从下载到3D目标检测全流程解析(附避坑技巧)

KITTI数据集实战指南&#xff1a;从下载到3D目标检测全流程解析&#xff08;附避坑技巧&#xff09; 1. 为什么选择KITTI数据集&#xff1f; 在计算机视觉和自动驾驶研究领域&#xff0c;数据是算法进步的基石。KITTI数据集自2012年发布以来&#xff0c;已成为全球最具影响力的…...

告别传统BPMN:wflow工作流设计器如何让普通员工5分钟搭建审批流程?

告别传统BPMN&#xff1a;wflow工作流设计器如何让普通员工5分钟搭建审批流程&#xff1f; 【免费下载链接】wflow workflow 工作流设计器&#xff0c;企业OA流程设计。表单流程设计界面操作超级简单&#xff01;&#xff01;普通用户也能分分钟上手&#xff0c;不需要专业知识…...

Cursor Pro功能扩展工具:技术原理与开源解决方案

Cursor Pro功能扩展工具&#xff1a;技术原理与开源解决方案 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached your trial re…...

LeRobot框架深度解析:3个核心模块实现机器人学习的PyTorch统一解决方案

LeRobot框架深度解析&#xff1a;3个核心模块实现机器人学习的PyTorch统一解决方案 【免费下载链接】lerobot &#x1f917; LeRobot: State-of-the-art Machine Learning for Real-World Robotics in Pytorch 项目地址: https://gitcode.com/GitHub_Trending/le/lerobot …...

2026年网盘性价比终极对决,10款网盘实测

上传龟速、下载受限、会员条约复杂——这是不少用户在2026年使用网盘时的真实痛点。面对市面上琳琅满目的云存储选项&#xff0c;很多人陷入了选择焦虑。为了解决这一问题&#xff0c;我们将视角聚焦于“效率”与“安全”&#xff0c;对市面上的10款主流网盘进行了系统性实测。…...

新手必看:GLM-4V-9B环境配置与简单调用,附完整代码示例

新手必看&#xff1a;GLM-4V-9B环境配置与简单调用&#xff0c;附完整代码示例 1. 环境准备与快速部署 1.1 硬件要求 GPU显存&#xff1a;至少24GB&#xff08;FP16精度&#xff09;或12GB&#xff08;INT4量化&#xff09;推荐配置&#xff1a;NVIDIA RTX 4090或更高性能显…...

Python张量框架选型不是技术问题,而是组织问题:CTO必须在立项前确认的5个战略问题(含人才储备周期、长期维护成本、专利风险审计清单)

第一章&#xff1a;Python张量框架选型不是技术问题&#xff0c;而是组织问题当团队在 PyTorch、TensorFlow 和 JAX 之间反复争论“哪个性能更好”或“哪个 API 更优雅”时&#xff0c;往往已陷入技术决定论的误区。真正制约张量框架落地效果的&#xff0c;是组织内部的协同惯性…...

ViGEmBus虚拟控制器驱动完全指南:从技术原理到场景落地的突破方案

ViGEmBus虚拟控制器驱动完全指南&#xff1a;从技术原理到场景落地的突破方案 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 价值定位&#xff1a;重新定义…...

虚拟控制器与设备模拟从入门到精通:ViGEmBus驱动技术指南

虚拟控制器与设备模拟从入门到精通&#xff1a;ViGEmBus驱动技术指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 在游戏开发与输入设备模拟领域&#xf…...

计算机毕业设计springboot基于的养老平台的设计与实现 SpringBoot架构下智慧养老综合服务系统的设计与实现 基于Java的社区养老数字化管理平台开发

计算机毕业设计springboot基于的养老平台的设计与实现&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。我国正加速步入老龄化社会&#xff0c;老年人口规模持续扩大&#xff0c;传…...