基于Python3的数据结构与算法 - 19 二叉搜索树

目录

一、二叉搜索树

1、二叉搜索树的插入

2、二叉搜索树的查找

3. 二叉搜素树的删除


一、二叉搜索树

  • 二叉搜索树是一颗二叉树且满足性质:设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key <= x.key ; 如果y是x右子树的一个节点,那么y.key > = x.key.
  • 二叉搜索树的操作:查询、插入、删除(查询和插入的时间复杂度为logn)

1、二叉搜索树的插入

示例代码如下:

class BirTreeNode:
    def __init__(self, data):
        self.data = data
        self.lchild = None  # 左孩子
        self.rchild = None  # 右孩子
        self.parent = None  # 父节点;相当于双链表


class BST:
    def __init__(self, li = None):
        self.root = None
        # self.root = None
        if li:
            for val in li:
                self.insert_no_rec(val)

    def insert(self, node, val):  # 插入函数(递归写法);node为当前插入的根节点
        node = BirTreeNode(node)
        if not node:  # 如果node为空
            node = BirTreeNode(val)
        elif val < node.data:  # 根节点比val大,插入左节点
            node.lchild = self.insert(node.lchild, val)
            node.lchild.parent = node
        elif val > node.data:  # 根节点比val大,此时node.rchild为根节点
            node.rchild = self.insert(node.rchild, val)
            node.rchild.parent = node
        return node
        # 如果等于,此时插入左边或右边都可以,默认没有等于这种情况
    def insert_no_rec(self ,val):  # 插入函数(非递归)
        p = self.root  #跟节点
        if not p:
            self.root = BirTreeNode(val)   # 空树
            return
        while True:
            if val < p.data:   # 往左子树走
                if p.lchild:   # p的左子树存在
                    p = p.lchild  # 根节点为左子树的孩子
                else:
                    p.lchild = BirTreeNode(val)
                    p.lchild.parent = p
            elif val > p.data:   #往右子树走
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = BirTreeNode(val)
                    p.rchild.parent = p
            else:
                return

    def pre_order(self, root):
        if root:  # 如果root不为空
            print(root.data, end=",")
            self.pre_order(root.lchild)
            self.pre_order(root.rchild)

    # 中序遍历
    def in_order(self,root):
        if root:
            self.in_order(root.lchild)
            print(root.data, end=',')
            self.in_order(root.rchild)

    # 后序遍历
    def post_order(self, root):
        if root:
            self.post_order(root.lchild)
            self.post_order(root.rchild)
            print(root.data, end=",")
        

tree = BST([4,6,7,9,2,1,3,5,8])
tree.post_order(tree.root)
print("")
tree.in_order(tree.root)
print("")
tree.post_order(tree.root)

输出结果如下所示:我们可以发现,中序遍历的结果一定是升序的!(对于二叉搜索树来说),因为中序遍历的遍历规则为先遍历左边,再遍历根节点,再遍历右边。 

2、二叉搜索树的查找

示例代码如下:

    def query(self, node, val):  # 查询函数(递归版)
        if not node:
            return None
        if node.data < val:  # 右边找
            return self.query(node.rchild, val)  # 往右边查找
        elif node.data > val:
            return self.query(node.lchild, val)
        return node

    def query_no_rec(self, val):  # 查询函数(非递归版)
        p = self.root
        while p:
            if p.data < val:
                p = p.rchild
            elif p.data > val:
                p = p.lchild
            else:
                return p
        return None

3. 二叉搜素树的删除

 删除操作分三种情况:

  1. 如果要删除的节点是叶子节点:直接删除

2. 如果要删除的节点只有一个孩子:将此节点的父亲与孩子连接,然后删除该节点。

此时如果要删除的节点是根,那么将子节点作为新根。 

3. 如果要删除的节点有两个孩子:将该节点删除,并其右子树的最小节点(该节点最多有一个右孩子)替换当前节点。

删除操作的代码示例如下:

    def __remove_node_1(self, node):  # 情况1,删除的点为叶子节点时
        if not node.parent:  # 这个树只有一个节点,既是叶子节点也是根节点
            self.root = None
        if node == node.parent.lchild:  # node是左孩子
            node.parent.lchild = None
        else:
            node.parent.rchild = None

    def __remove_node_2_1(self, node):  # 情况2_1,node只有一个左孩子
        if not node.parent:  # 判断是否为根节点
            self.root = node.lchild
            node.lchild.parent = None
        elif node == node.parent.lchild:  # node为左孩子
            node.parent.lchild = node.lchild  # 爷孙相连
            node.lchild.parent = node.parent
        else:
            node.parent.rchild = node.lchild  # node为右孩子
            node.parent.rchild = node.parent

    def __remove_node_2_2(self, node):  # node只有一个右孩子
        if not node.parent:
            self.root = node.rchild
        elif node == node.parent.lchild:  # node为左孩子
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent
        else:
            node.parent.rchild = node.rchild
            node.rchild.parent = node.parent

    def delete(self, val):  # 因为删除操作有三种情况,因此在写删除操作之前需要先将其他集几种情况写下来
        if self.root:  # 不是空树
            node = self.query_no_rec(val)  # 先查询到要删除的节点
            if not node:  # node不存在
                return False
            if not node.lchild and not node.rchild:  # 既没有左孩子也没有右孩子,即删除的节点为叶子节点
                self.__remove_node_1(node)
            elif not node.rchild:  # 只有左孩子,2_1
                self.__remove_node_2_1(node)
            elif not node.lchild:  # 只有右孩子
                self.__remove_node_2_2(node)
            else:  # 情况三:有两个子节点,将该节点删除,将右子树的最小节点替换至该节点
                min_node = node.rchild  # 从右子树开始寻找
                while min_node.lchild:  # 一直往左走,走到头就找到最小节点
                    min_node = min_node.lchild  # 循环结束找到最小节点
                node.data = min_node.data  # 将min的最小值替换到节点位置
                # 接下来将min_node删除,此时min_node有三种删除情况,但是min_node肯定没有左孩子,只能是叶子节点或只有一个右孩子
                if min_node.rchild:
                    self.__remove_node_2_2(min_node)
                else:
                    self.__remove_node_1(min_node)

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

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

相关文章

Rust之构建命令行程序(五):环境变量

开发环境 Windows 11Rust 1.77.0 VS Code 1.87.2 项目工程 这次创建了新的工程minigrep. 使用环境变量 我们将通过添加一个额外的功能来改进minigrep:一个不区分大小写的搜索选项&#xff0c;用户可以通过环境变量打开该选项。我们可以将此功能设置为命令行选项&#xff0c;…

Python模块与包管理使用pip与virtualenv【第151篇—模块与包管理】

Python模块与包管理&#xff1a;使用pip与virtualenv 在Python开发中&#xff0c;模块和包管理是至关重要的&#xff0c;它们使得代码的组织、重用和共享变得更加简单和高效。本文将介绍两个Python生态系统中最常用的工具&#xff1a;pip和virtualenv。通过这些工具&#xff0…

UE5 C++ 3D血条 响应人物受伤 案例

一.3Dwidget 1.创建C Userwidget的 MyHealthWidget&#xff0c;声明当前血量和最大血量 UCLASS() class PRACTICEC_API UMyHealthWidget : public UUserWidget {GENERATED_BODY() public:UPROPERTY(EditAnywhere,BlueprintReadWrite,Category "MyWidget")float C…

java中异常类

异常 异常体系继承结构 Throwable类是 Java 语言中所有错误或异常的超类&#xff0c;只有当对象是此类&#xff08;或其子类之一&#xff09;的实例时&#xff0c;才能通过 Java 虚拟机或者 Java throw 语句抛出。     异常是对象&#xff0c;而对象都采用类来定义。异常的…

C语言之strcspn用法实例(八十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

使用jupyter-Python进行模拟股票分析

tushare财经数据接口包 pip install tushare作用&#xff1a;提供相关指定的财经数据 需求&#xff1a;股票分析 使用tushare包获取某股票的历史行情数据 输出该股票所有收盘比开盘上涨3%以上的日期 输出该股票所有开盘比前日收盘跌幅超过2%的日期 假如我从2015年1月1日开…

Ubuntu 22.04安装Python3.10.13

Ubuntu最好设置为英文&#xff0c;我之前用中文在make的test的时候&#xff0c;总是会有fail。 查了下有人怀疑是language的问题&#xff0c;保险起见都用英文&#xff0c;个人实践也证明改为英文就不报错了。 issue 44031: test_embed and test_tabnanny fails if the curre…

【算法刷题 | 二叉树 02】3.21 二叉树的层序遍历01(5题:二叉树的层序遍历、层序遍历||、右视图、层平均值,以及N叉树的层序遍历)

文章目录 5.二叉树的层序遍历5.1 102_二叉树的层序遍历5.1.1问题5.1.2解法&#xff1a;队列 5.2 107_二叉树的层序遍历||5.2.1问题5.2.2解法&#xff1a;队列 5.3 199_二叉树的右视图5.3.1问题5.3.2解决&#xff1a;队列 5.4 637_二叉树的层平均值5.4.1问题5.4.2解决&#xff1…

Dell戴尔XPS 12 9250二合一笔记本电脑原装出厂Windows10系统包下载

链接&#xff1a;https://pan.baidu.com/s/1rqUEM_q5DznF0om6eevcwg?pwdvij0 提取码&#xff1a;vij0 戴尔原厂WIN10系统自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志、系统属性专属LOGO标志、Office办公软件、MyDell等预装程序 文件格式&#xff1a;esd/wim/sw…

API调试管理工具Postman下载及操作介绍

1.下载安装postman地址&#xff1a;https://www.getpostman.com/downloads/ 2.创建项目 3.创建请求API 然后点击save保存api 4.用一个变量保存主域名&#xff0c;方便后续操作 就类似下面的baseurl 5.创建新环境 6.添加变量&#xff08;如添加本地测试环境url——ba…

Qt如何直接处理系统事件(比如鼠标事件),而不是post事件

#include <QtGui/5.15.2/QtGui/qpa/qwindowsysteminterface.h> // 方便调试事件 QWindowSystemInterface::setSynchronousWindowSystemEvents(true); 直接再 qWindowsWndProc函数中处理 通常情况: 事件被放到一个队列中

Leetcode 101. 对称二叉树

心路历程&#xff1a; 这道题没有想象中那么简单。其最难的地方就在于如何判断两个子树相等这件事上&#xff0c;无法直接left right&#xff0c;因为毕竟只是指针。 本道题思考了三种解法&#xff0c;其中一种很可惜没有完全AC。 注意的点&#xff1a; 1、root.left root…

浙江IGM机器人K5控制柜维修需要注意哪些问题?

IGM机器人K5控制柜常见故障及维修方法 1、电源故障&#xff1a; 表现为IGM机器人K5控制柜不能开机或突然断电。 检查&#xff1a;检查电源线是否连接良好&#xff0c;有无破损&#xff1b;检查电源模块的输出电压是否正常&#xff1b; 维修方法&#xff1a;如电源模块损坏&…

【并查集专题】【蓝桥杯备考训练】:网络分析、奶酪、合并集合、连通块中点的数量、格子游戏【已更新完成】

目录 1、网络分析&#xff08;第十一届蓝桥杯省赛第一场C A组/B组&#xff09; 2、奶酪&#xff08;NOIP2017提高组&#xff09; 3、合并集合&#xff08;模板&#xff09; 4、连通块中点的数量&#xff08;模板&#xff09; 5、格子游戏&#xff08;《信息学奥赛一本通》…

DashVector - 阿里云向量检索服务

DashVector 文章目录 DashVector一、关于 DashVector二、使用 DashVector 前提准备1、创建Cluster&#xff1a;2、获得API-KEY3、安装最新版SDK 三、快速使用 DashVector1. 创建Client2. 创建Collection3、插入Doc4、相似性检索5、删除Doc6. 查看Collection统计信息7. 删除Coll…

jeect-boot queryFieldBySql接口RCE漏洞(CVE-2023-4450)复现

jeect-boot积木报表由于未授权的 API /jmreport/queryFieldBySql 使用了 freemarker 解析 SQL 语句从而导致了 RCE 漏洞的产生。 1.漏洞级别 高危 2.漏洞搜索 fofa app"Jeecg-Boot 企业级快速开发平台"3.影响范围 JimuReport < 1.6.14.漏洞复现 这个漏洞的…

(done) 机器学习中的方差 variance 和 偏差 bias 怎么理解?

来源&#xff1a;https://blog.csdn.net/weixin_41479678/article/details/116230631 情况1属于&#xff1a;低 bias&#xff0c;高 variance (和 human performance 相近&#xff0c;但和 验证集dev set 相远) 通常意味着模型训练轮数太多 情况2属于&#xff1a;高 bias&#…

uniapp自定义导航栏左中右内容和图标,以及点击事件

uniapp自定义导航栏左中右内容和图标&#xff0c;以及点击事件 效果&#xff1a; 页面&#xff1a; <view class"navigation-bar"><view class"navigation-bar-left" click"navigateBack"><u-icon name"arrow-left"…

StarRocks-2.5.13部署安装

1、安装jdk11 tar xf jdk-11.0.16.1_linux-x64_bin.tar.gz mv jdk-11.0.16.1 /data/soft/jdk-11 # 配置在/etc/profile中 export JAVA_HOME/data/soft/jdk-11 export CLASSPATH.:/data/soft/jdk-11/lib export PATH/data/soft/jdk-11/bin:$PATH # 验证jdk [rootdb-public-03 s…

就业班 第二阶段 2401--3.19 day4 主从复制

一、MySQL-Replication&#xff08;主从复制&#xff09; 1.1、MySQL Replication 主从复制&#xff08;也称 AB 复制&#xff09;允许将来自一个MySQL数据库服务器&#xff08;主服务器&#xff09;的数据复制到一个或多个MySQL数据库服务器&#xff08;从服务器&#xff09;…