数据结构——二叉搜索树

一、二叉搜索树概念

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

(1)若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值;

(2)若它的右子树不为空,则右子树上的所有节点的值都大于根节点的值;

(3)它的左右子树也分别为二叉搜索树。

二、二叉搜索树操作

1.二叉搜索树的查找

(1)若根节点为空,则直接返回false,否则进行后续操作;

(2)如果根节点key==查找key,返回ture,否则进行后续操作;

(3)若根节点key>查找key,则在其左子树内进行查找,否则在其右子树内进行查找;

(4)递归上述过程。

2.二叉搜索树的插入

(1)若树为空,则直接插入;

(2)若树不为空,则按二叉搜索树性质查找插入位置,然后插入。

3.二叉搜索树的删除

        首先查找待删除元素是否在二叉搜索树中,没有则直接返回,否则要删除的节点可分为以下四种情况:

(1)待删除节点无孩子节点;

(2)待删除节点只有左孩子;

(3)待删除节点只有右孩子;

(4)待删除节点左右孩子都有。

删除方法:

情况(1):删除方法与情况(2)和(3)相同;

情况(2):删除该节点,并使被删除节点的双亲节点指向被删除节点的左孩子节点;

情况(3):删除该节点,并使被删除节点的双亲节点指向被删除节点的右孩子;

情况(4):在它的右子树中寻找中序下的第一个节点(值最小的节点),用它的值覆盖掉被删除节点,在处理该节点的删除问题。或找它左子树中最大的节点。

三、二叉搜索的实现

1.代码实现

template<class T>
struct BSTNode {
	BSTNode(const T& value = T())
		: _left(nullptr)
		, _right(nullptr)
		, _value(value)
	{}

	BSTNode<T>* _left;
	BSTNode<T>* _right;
	T _value;
};

//约定value唯一
template<class T>
class BinarySearchTree {
	typedef BSTNode<T> Node;
public:
	BinarySearchTree()
		: _root(nullptr)
	{}

	~BinarySearchTree() {
		Destroy(_root);
	}

	//插入
	bool Insert(const T& value) {
		//空树
		if (_root == nullptr) {
			_root = new Node(value);
			return true;
		}
		//非空
		Node* cur = _root;
		Node* parent = nullptr;//保存cur双亲节点
		//查找插入位置
		while (cur) {
			parent = cur;
			if (value < cur->_value) {
				cur = cur->_left;
			}
			else if (value > cur->_value) {
				cur = cur->_right;
			}
			else {//待插入节点已存在
				return false;
			}
		}
		//插入新节点
		cur = new Node(value);
		if (value > parent->_value) {
			parent->_right = cur;
		}
		else {
			parent->_left = cur;
		}
		return true;
	}

	//查找
	Node* Find(const T& value) {
		Node* cur = _root;
		while (cur) {
			if (value == cur->_value) {
				return cur;
			}
			else if (value < cur->_value) {
				cur = cur->_left;
			}
			else {
				cur = cur->_right;
			}
		}
		return cur;
	}

	//删除
	bool Erase(const T& value) {
		if (_root == nullptr) return false;
		Node* cur = _root;
		Node* parent = nullptr;
		//查找待删除节点
		while (cur) {
			//parent = cur;不能在这里记录双亲节点,因为有可能cur已经是待删除节点,会直接break
			if (value == cur->_value) {
				break;
			}
			else if (value < cur->_value) {
				parent = cur;
				cur = cur->_left;
			}
			else {
				parent = cur;
				cur = cur->_right;
			}
		}
		if (cur == nullptr) return false;//没有待删除节点
		//删除节点
		if (cur->_left == nullptr) {//情况1和2
			if (parent == nullptr) {//是根节点且左孩子为空
				_root = cur->_right;
			}
			else {//不是根节点
				if (cur == parent->_left) parent->_left = cur->_right;
				else parent->_right = cur->_right;
			}
			delete cur;
		}
		else if (cur->_right == nullptr) {//情况1和3
			if (parent == nullptr) {//是根节点且右孩子为空
				_root = cur->_left;
			}
			else {//不是根节点
				if (cur == parent->_left) parent->_left = cur->_left;
				else parent->_right = cur->_left;
			}
			delete cur;
		}
		else {//情况4
			//查找该节点右子树最小值(或左子树的最大值)
			Node* prev = cur;
			Node* node = cur->_right;
			while (node->_left) {
				prev = node;
				node = node->_left;
			}
			//覆盖节点值
			cur->_value = node->_value;
			//删除节点,该节点的左孩子肯定为空
			if (node == prev->_left) prev->_left = node->_right;
			else prev->_right = node->_right;
			delete node;
		}
		return true;
	}


	//中序遍历
	void InOrder() {
		_InOrder(_root);
		std::cout << std::endl;
	}


private:
	//中序遍历
	void _InOrder(Node* root) {
		if (root == nullptr) return;
		_InOrder(root->_left);
		std::cout << root->_value << " ";
		_InOrder(root->_right);
	}
	//销毁
	void Destroy(Node*& root) {
		//利用后续遍历销毁
		if (root == nullptr) return;
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
		root = nullptr;
	}

private:
	Node* _root;
};

2.性能分析

        二叉搜索树的插入、删除操作都必须先进行查找,查找效率代表了二叉搜索树的各个操作的性能。而二叉树的结构,取决于给定的序列:

(1)最优情况下:二叉搜索树为完全二叉树,其平均比较次数为log_{2}^{N}

(2)最坏情况下:二叉搜索树退化为单支树,其平均比较次数为N/2;

所以二叉搜索树的查找、插入、删除时间复杂度都是O(N)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode-718. 最长重复子数组

目录题目思路动态规划遇到的坑动态规划(优化)题目来源 718. 最长重复子数组 题目思路 用二维数组可以记录两个字符串的所有比较情况&#xff0c;这样就比较好推递推公式了。 动态规划 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]的定义也就决定…

【云原生】我将ChatGPT变成Kubernetes 和Helm 终端

{kubectl get po&#xff0c;deploy&#xff0c;svc}{kubectl run --imagenginx nginx-app --port80 --env“DOMAINcluster”}{kubectl expose deployment nginx-app --port80 --namenginx-http}{kubectl get po&#xff0c;svc&#xff0c;deploy}{curl 10.100.67.94:80}{helm…

Spring事务

目录 手动操作 声明式提交 注解的属性 事务隔离级别 事务传播机制 事务可以将一组操作封装成为一个单元&#xff0c;一组操作要么全部成功&#xff0c;要么全部失败 Mysql中操作事务&#xff0c;有三个步骤&#xff1b; 1、start transaction &#xff1b;开启事务 2、com…

springboot 整合Mybatis-Plus分页、自动填充功能

springboot 整合Mybatis-Plus分页、自动填充功能功能 此次分页、自动填充功能的实现是在Spring Boot整合 druid、Mybatis-plus实现的基础上完成的&#xff0c;包括数据源配置、各种依赖添加、mapper和service的实现。不在重复记录。 Java开发手册要求数据表必须要有三个字段&am…

【lwIP(第九章)】ICMP协议

目录一、ICMP协议简介1. ICMP协议类型与结构2. ICMP 差错报文3. ICMP 查询报文二、ICMP协议原理1. ICMP报文数据结构2. ICMP的差错报文3. 差错报文的原理4. ICMP的查询报文一、ICMP协议简介 ICMP协议是一个网络层协议。 一个新搭建好的网络&#xff0c;往往需要先进行一个简单的…

为什么说学人工智能一定要学Python?

学习人工智能需要掌握大量的数据处理和算法实现&#xff0c;而Python作为一种高级编程语言&#xff0c;具有简单易学、灵活多变、开源丰富的库等优点&#xff0c;成为了人工智能领域广泛应用的语言之一。 具体来说&#xff0c;Python在人工智能中的优势包括&#xff1a; ​​…

Matlab群体智能优化算法之巨型睡莲优化算法(VAO)

Matlab群体智能优化算法之巨型睡莲优化算法(VAO) 摘要&#xff1a;介绍一种新型智能优化算法&#xff0c;巨型睡莲优化算法。其应用于24个基准测试函数&#xff0c;并与其他10个著名算法进行了比较。提出的算法在10个优化问题上进行了测试&#xff1a;最小生成树、枢纽位置分配…

Nginx学习(9)—— 负载均衡模块

文章目录Nginx负载均衡模块负载均衡配置指令钩子初始化配置初始化请求peer.get和peer.free回调函数小结Nginx负载均衡模块 负载均衡模块用于从”upstream”指令定义的后端主机列表中选取一台主机。nginx先使用负载均衡模块找到一台主机&#xff0c;再使用upstream模块实现与这…

HTTP代理端口是什么意思?

HTTP代理端口是指代理服务器所使用的端口。代理服务器是一种介于客户端和服务器之间的计算机系统&#xff0c;它可以拦截客户端发送给服务器的请求&#xff0c;并将其转发到服务器。而HTTP代理端口则是代理服务器上专门用于处理HTTP请求和响应的端口号。默认情况下&#xff0c;…

【Java】JavaSE概要

整理&#xff1a;【狂神说Java】JavaSE阶段回顾总结_哔哩哔哩_bilibili JavaSE概要 简介 JDK&#xff1a;开发者工具包 JRE&#xff1a;运行环境 //Hello.java public class Hello{public static void main(String[] args){System.out.println("Hello,World!");} }…

Redis数据库

一、关系数据库与非关系型数据库概述 1、关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 SQL 语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语…

Spring Boot基础学习之(六):前后端交互实现用户登录界面

本篇博客写的内容&#xff0c;是一个系列&#xff0c;内容都是关于spring boot架构的学习&#xff0c;实现前后端交互&#xff0c;极大的解放双手spring boot学习系列这是关于spring boot的专栏&#xff0c;后期也会不定期进行更新。内容都是有序号的&#xff0c;一步接着一步。…

有人物联口红DTU DR154配置与RS 485传感器数据处理

一、硬件设备 &#xff08;1&#xff09;有人物联口红DTU DR154&#xff08;RS 485版本&#xff09; 这个DTU非常给力&#xff0c;不用插卡自带esim卡&#xff0c;送8年流量&#xff0c;配置的话通过小程序【联博士】蓝牙配置&#xff08;手机扫描DTU背后的二维码即可&#x…

界面开发框架Qt新手入门教程 - 项目视图示例介绍

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。Qt提供了许多功能&…

java基础问答

57、synchronized 各种加锁场景的作用范围 1.作用于非静态方法&#xff0c;锁住的是对象实例&#xff08;this&#xff09;&#xff0c;每一个对象实例有一个锁。 public synchronized void method() {} 2.作用于静态方法&#xff0c;锁住的是类的Class对象&#xff0c;因为Cl…

chatgpt+安全机器人控制器+底盘一体化方案设计构想

“你有没有想过&#xff0c;你只需告诉你的家庭助理机器人&#xff1a;‘请加热我的午餐’&#xff0c;它就会自己找到微波炉。这是不是很神奇&#xff1f;” 近日&#xff0c;微软在其官网发表了一篇名为《机器人 ChatGPT&#xff1a;设计原则和模型能力&#xff08;ChatGPT …

MongoDB 6.0 入门(一)

为什么研究MongDB 6.0 今天和老大聊天 聊到了一个场景的设计&#xff0c;我刚开始推荐了 clickhouse &#xff0c;然后老大指出 前两天 测试的结果&#xff0c;因为clickhouse 因为 是列式存储&#xff0c;导致我们要查询一行数据&#xff0c;需要200ms&#xff08;库中有2000…

MyBatis源码分析(二、续)SqlSource创建流程,SQL如何解析?如何将#{id}变成?的

文章目录实例一、SqlSource处理入口二、SqlSource处理逻辑1、XMLScriptBuilder 构造方法2、解析动态sql3、DynamicSqlSource4、RawSqlSource解析sql&#xff08;1&#xff09;parse方法解析sql写在后面实例 此处我们分析的sql&#xff1a; <select id"selectBlog&quo…

redis 十. 线程基础

目录一. redis 基础复习与了解redis6二. redis 线程问题总结一. redis 基础复习与了解redis6 redis官网, redis中文网站, redis命令参考网站此处以redis6.0.8或以上版本为例(查看自己redis版本命令"redis- server -v")按照redis6以上版本测试使用时,redis.conf下需要…

Baklib:企业知识管理帮助文档制作平台

在当今的商业环境中&#xff0c;企业面临着越来越多的挑战。其中之一是如何管理并传递企业内部的知识。企业知识管理的重要性不言而喻&#xff0c;它可以帮助企业更好地组织和利用内部的知识资源&#xff0c;提高生产力和竞争力。而Baklib作为一款企业知识管理&帮助文档制作…