【数据结构】详解二叉搜索树及其实现

news2024/9/24 10:58:13

前言:

二叉搜索树是红黑树等的前身,掌握其操作和性质很重要。总结自用and分享。


目录

一、基本概念

二、其常见操作及其实现

1.定义节点

2.查找元素 

 3.插入元素

4.删除元素【难点】

 三、性质分析


一、基本概念

        如下所示:对于所有节点都满足该性质:子树上所有节点的值都小于该节点的值。对于每个节点,右子树上所有节点的值都大于该节点的值。每个节点的左子树和右子树也是一个二叉搜索树。

其也叫二叉排序树,对其进行中序遍历可以得到排好序的序列。

二、其常见操作及其实现

1.定义节点

public class BinarySearchTree {
    private TreeNode root = null;//根节点


    // 定义节点
    class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
}

2.查找元素 

思想:

运用一个递归的思想:

1.先看看根节点是不是该元素,是的话,直接当前节点。

2.若不是,判断其位置,若该元素比根大,那就去右子树找(跳到1)。

3.若该元素比根小,那就去左子树找(跳到1)。

4.若遍历完所有节点都找不到,返回null。

代码实现:

public TreeNode search(int val) {
        TreeNode curRoot = root;//当前的双亲节点
        while (curRoot != null) {
            if (curRoot.val == val) {
                return curRoot;
            } else if (curRoot.val > val) {
                curRoot = curRoot.left;
            } else {
                curRoot = curRoot.right;
            }
        }
        return null;
    }

 3.插入元素

注意:二叉树的插入是不会破坏原有的结构的,插入元素,总是能找到合适的叶子节点插入,你们可以画图感受一下。

思想:

1.若该树为空,直接插入。

2.若树不为空:根据二叉树的性质,找到它的容身之处的双亲节点。

3.找到双亲节点之后,若比双亲节点大,插入其右边,若比双亲节点小,插入其左边。

代码实现:

    // 2.插入元素
    public boolean insert(int val) {

        // 如果根节点为空,直接插入,返回true
        if (root == null) {
            root = new TreeNode(val);
            return true;
        }

        TreeNode cur = root;
        TreeNode parent = null;

        while (cur != null) {
            if (val == cur.val) {
                System.out.println("值为" + val + "的节点已经存在");
                return false;
            } else if (val > cur.val) {
                parent = cur;
                cur = cur.right;
            } else {
                parent = cur;
                cur = cur.left;
            }
        }

        // 抵达该位置时,已经找到合适的插入位置的双亲节点:parent
        // 要判断一下插入哪一边
        if (val > parent.val) {
            parent.right = new TreeNode(val);
        } else {
            parent.left = new TreeNode(val);
        }
        return true;
    }

4.删除元素【难点】

注意:刚说的插入元素不会破坏原有的树结构,但是删除元素就可能不得不破坏原有的树结构了,毕竟要把某个在中间的元素搬走...

a:初步思路:

    先找到该节点和其双亲节点,若找不到该节点,返回false。若找到了该节点,再根据情况进行删除调整。

 public boolean remove(int val) {
        TreeNode cur = root;
        TreeNode parent = null;

        while (cur != null) {
            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > val) {
                parent = cur;
                cur = cur.left;
            } else {
                //找到要删除的元素和其双亲节点了
                removeNode(parent, cur);
                return true;
            }
        }
        System.out.println("删除失败,没找到值为"+val+"的节点");
        return false;
    }

 b:删除:(难点)

  1. 删除叶子节点:直接删除。
  2. 删除只有一边子节点的节点:用子节点替代该节点。(可涵盖情况1)
  3. 删除有两个子节点的节点【难点所在】:找到该节点的中序后继节点,用它的值替换被删除节点的值,然后删除该中序后继节点,并把该中序后继节点的子节点继承过去。

 再捋一下删除的情况:

     情况1、2: 我们找到了要删除的节点和其双亲节点。上述的情况2是可以包含情况1的:叶子节点也可以视为只有一边子节点(实际是null)的节点,然后子节点(实际是null),替代原本的节点。但是有一种情况我们要特殊处理,那就是要删除的节点是根节点时(此时对parent修改,只是流动了parent,影响不了root),我们需要直接拿到root去修改指向。

      情况3: 删除有两个子节点的节点【难点所在】

      找到要删除节点的右子树的最左节点,我们因为是最左节点,该节点肯定没有左子树了。

        我们把最左节点的值直接覆盖到要删除的节点,原因:最左节点是要删除节点的右子树里最小的,把它放在要删除的节点处,既可以满足,右子树中所有元素比节点大,也可以满足本来左子树中所有元素比节点小。(天然,右子树中任一元素大于左子树中的)

        善后阶段:最左节点的值已经被拿去,应该要删掉。这时候就回到情况1、2的问题了,且最左节点肯定不是头结点,处理起来也更简单。

private void removeNode(TreeNode parent, TreeNode cur) {
        // 情况1:要删除的节点没有左子节点
        if (cur.left == null) {
            // 如果要删除的节点是根节点,则直接将根节点指向其右子节点
            if (cur == root) {
                root = cur.right;
            } else if (cur == parent.left) {
                // 如果要删除的节点是其父节点的左子节点,则更新父节点的左指针
                parent.left = cur.right;
            } else {
                // 如果要删除的节点是其父节点的右子节点,则更新父节点的右指针
                parent.right = cur.right;
            }
        }
        // 情况2:要删除的节点没有右子节点
        else if (cur.right == null) {
            // 如果要删除的节点是根节点,则直接将根节点指向其左子节点
            if (cur == root) {
                root = cur.left;
            } else if (cur == parent.left) {
                // 如果要删除的节点是其父节点的左子节点,则更新父节点的左指针
                parent.left = cur.left;
            } else {
                // 如果要删除的节点是其父节点的右子节点,则更新父节点的右指针
                parent.right = cur.left;
            }
        }
        // 情况3:要删除的节点有左右子节点
        else {
            // 找到要删除节点的右子树中的最左(最小)节点
            TreeNode t = cur.right;
            TreeNode tp = cur;
            while (t.left != null) {
                tp = t;
                t = t.left;
            }
            // 将最左节点的值赋值给要删除的节点
            cur.val = t.val;

            // 删除最左节点,更新其父节点的左指针或右指针
            if (tp.left == t) {
                tp.left = t.right;
            } else {
                tp.right = t.right;
            }
        }
    }

 三、性质分析

        由于二叉搜索树的特点,平均情况下,插入、查找和删除操作的时间复杂度都是 O(log⁡n)。但是,如果二叉搜索树退化成一条链表(例如插入有序数据),最坏情况下,操作时间复杂度会降到 O(n)。为了避免这种情况,实际应用中常使用平衡二叉搜索树(如AVL树、红黑树等)。

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

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

相关文章

小阿轩yx-Kubernetes高级调度

小阿轩yx-Kubernetes高级调度 前言 前面 Kubernetes 的调度基础实现了见表格自己的服务器部署到 Kubernetes在生产环境中&#xff0c;调度远比想象的要复杂 比如 某些程序只能部署在固定的几台机器上某些机器只能部署指定的 Pod节点挂了怎么快速修复节点挂了如何让影响最小…

DDS基本原理--FPGA学习笔记

DDS信号发生器原理&#xff1a; timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2024/09/04 15:20:30 // Design Name: hilary // Module Name: DDS_Module //module DDS_Module(Clk,Reset_n,Fword,Pword,Data);input Clk;input Reset_n;input [31:0]…

OpenBLAS QR decompose example

1. 安装 OpenBLAS release 版本&#xff1a; Makefile&#xff1a; all:wget https://github.com/OpenMathLib/OpenBLAS/archive/refs/tags/v0.3.27.tar.gztar zxf v0.3.27.tar.gz make -C OpenBLAS-0.3.27 FCgfortran -jinstall:make -C OpenBLAS-0.3.27 install PREFIX../lo…

字节跳动一面

字节跳动一面【C后端开发】 base &#xff1a; 深圳 岗位&#xff1a;C后端开发 时间&#xff1a; 2024/8/30 文章目录 基本介绍C语言1. 堆栈内存是否连续&#xff0c;为什么&#xff1f;2. int i0; i ; 两个线程同时执行10000次&#xff0c;i最终的数值是多少&#xff1f;3.…

【Java基础】代理

文章目录 代理代理模式的优点代理模式类型基于JDK的静态代理基于JDK的动态代理 代理 一种设计模式&#xff0c;不允许用户直接访问核心功能&#xff0c;而是通过代理来访问核心类的核心功能 举个例子&#xff0c;如果我们现在需要一个银行转账系统&#xff0c;我们需要在一个Ja…

git创建本地分支并track跟踪远程分支

git创建本地分支并track跟踪远程分支 查看本地分支与远程分支的映射关系&#xff1a; git branch -vv 查看远程都有什么分支&#xff1a; git branch -r 在本地自动新建一个xxx分支&#xff0c;且自动track跟踪远程的同名xxx分支&#xff1a; git checkout --track origin/xx…

MinIO Packet Pushers 播客: 汤姆-里昂,《NFS 必死》。

我们真的很喜欢 Packet Pushers 的团队。他们的播客是业内最好的播客之一&#xff0c;涵盖了从堆栈顶部到底部的技术。我们最近有机会赞助传奇人物 Tom Lyon 对 Ethan Banks 和 Drew Conry-Murray 的采访。Packet Pushers 的团队对 Tom 最近题为“NFS&#xff08;网络文件系统&…

数据结构(13)——平衡二叉树(红黑树)

欢迎来到博主的专栏——数据结构 博主ID&#xff1a;代码小号 文章目录 红黑树红黑树节点之间的关系红黑树的插入uncle节点为红色uncle节点是黑色或者没有uncle节点 红黑树 平衡二叉树最出名的除了AVL树之外就是红黑树&#xff08;RBTree&#xff09;&#xff0c;所谓红黑树&a…

JSON 格式详解

JSON 格式详解 随着互联网的发展和各种 Web 应用程序的普及&#xff0c;数据交换已经成为了我们日常开发中的重要环节。而在各种数据交换格式中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&#xff0c;以其简洁、易于阅…

2024.9.4(k8s)

一、前期准备 1、配置主机映射 [rootk8s-master ~]# vim /etc/hosts 192.168.8.168 k8s-master 192.168.8.176 k8s-node1 192.168.8.177 k8s-node2[rootk8s-master ~]# ping k8s-master 2、配置yum源 [rootk8s-master yum.repos.d]# vim kubernetes.repo [kubernetes] n…

智能医学(二)——MDPI特刊推荐

特刊征稿 01 特刊名称&#xff1a; eHealth and mHealth: Challenges and Prospects, 2nd Volume 参与期刊&#xff1a; 截止时间&#xff1a; 摘要提交截止日期 关闭(2024年6月30日) 投稿截止日期 2024年9月30日 目标及范围&#xff1a; 关键字 l 人工智能 l 计算机…

模拟实现string类及体验传统深拷贝

目录 strcpy 构造函数 优化 拷贝构造/深拷贝 operator size/operator[] operator<< c_str() 模拟string::iterator 插入 push_back() append() operator reserve npos strcpy strcpy是将/0拷贝完成后才会停止。 构造函数 string():_str(nullptr) {} st…

vite 打包 学习

plugins.jsimport vue from "vitejs/plugin-vue"; // 自动引入插件 import autoImport from "unplugin-auto-import/vite"; import setupExtend from "unplugin-vue-setup-extend-plus/vite"; import { ElementPlusResolver } from unplugin-vue…

国内Etsy开店注册账号需要什么?

Etsy作为海外知名二手电商平台&#xff0c;对于原创手工产品的商家来说具有巨大的市场流量与商机&#xff0c;但注册Etsy账号对于国内跨境电商用户来说确实存在一定的难度&#xff0c;作为Etsy也是小有名气的小商家&#xff0c;今天也分享一下开店的经验帮助大家出海。 一、Ets…

终端安全一体化解决方案有哪些?值得收藏的五款终端安全系统

随着信息技术的迅猛发展&#xff0c;企业和个人面临着越来越多的安全威胁。终端作为连接互联网和用户的第一线&#xff0c;其安全性直接影响到整个网络乃至组织的安全态势。为了应对日益复杂的网络环境&#xff0c;许多企业开始采用终端安全一体化解决方案&#xff0c;以期达到…

EVPN学习

三、VXLAN BGP EVPN基本原理_vxlan的type2,type3区别-CSDN博客 华为数通笔记VXLAN&BGP EVPN_vxlan为什么用bgp协议-CSDN博客

【MeterSphere】vnc连接不上selenium-chrome容器

目录 一、现象 二、查看配置文件 docker-compose-seleniarm.yml 三、处理 3.1 删除上图当中的三行 3.2 msctl reload 3.3 重新连接 前言:使用vnc连不上ms的selenium-chrome容器,看不到里面运行情况,以前其实可以,后来不行了,研究了一下 一、现象 输入IP:端口,连…

vmware 17.6 pro for personal USE初体验

新学期开学了&#xff0c;暑假期间把台式机放在办公室远程&#xff0c;无赖期间经常断电&#xff0c;把我的老台给烧坏了&#xff0c;检测了下固态硬盘和机械硬盘&#xff0c;好歹能用。但是win11的系统奔溃了。就花了半天时间重装。*v* 悲剧的是&#xff0c;一些软件环境必须…

怎么合并pdf文件?6个PDF文件合并成一个,只需要这5步!

在日常工作和学习中&#xff0c;我们经常需要处理多个PDF文件&#xff0c;有时为了方便查阅和管理&#xff0c;需要将它们合并成一个文件。以下是几种实用的方法来合并PDF文件&#xff0c;特别是如何将6个PDF文件合并成一个。 PDF合并工具推荐1. 金舟PDF编辑器 第一步、从金舟…

php民宿短租平台Java民宿预约系统python民宿预订住宿与可视化分析系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…