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

手写一个二叉搜索树(BST)

前言

在上一篇写了一个简单的双向链表,难度是简简单单,这次来尝试二叉树,难度是也还行吧,多少有点夸张的成分了,不过对于大佬来说这些就是简简单单。

难度列表:

  • 集合:有手就行
  • 链表:简简单单
  • 队列:基础操作
  • 二叉树:也还行吧
  • 平衡二叉树:普普通通
  • 红黑树:有点难度了
  • 堆/栈:难度提升了
  • :今天是高端局

属性

二叉树是有一个根节点的,大部分操作都是基于根节点进行向下处理,所以需要显式的定义一个根节点root。

private Node root;

二叉树的每个节点都有左右节点跟它自身的属性值,所以Node内容中需要有左右节点的属性leftright,至于自身属性Demo还是用数值类型Integer

代码如下:

    private class Node{
        private Node left;
        private Node right;
        private Integer data;
        
        public Node(Integer data){
            this.data = data;
        }
        
    }

ADD

第一步:判断root是否为空,为空则初始化root节点,否则执行add方法

    private void add(int data) {
        if (Objects.isNull(root)){
            root = new Node(data);
        }else{
            root.add(data);
        }
    }

第二步:add方法,判断参数值是否小于节点值,小于挪移到左节点处理,大于挪移到右节点处理

        private void add(Integer data) {
            if (this.data >= data){
                // left
            }else{
                // right
            }
        }

第三步:判断左/右节点是否为空,为空则初始化节点,否则递归进行add方法

        private void add(Integer data) {
            if (this.data >= data){
                if (Objects.isNull(this.left)){
                    this.left = new Node(data);
                }else{
                    this.left.add(data);
                }
            }else{
                if (Objects.isNull(this.right)){
                    this.right = new Node(data);
                }else{
                    this.right.add(data);
                }
            }
        }

GET

二叉搜索树查询值有三种遍历方式:

  • 前序遍历
  • 中序遍历
  • 后续遍历

这里不每一个都将了,就选择最常用的中序遍历作为我们查询值内容的遍历方式

代码如下:

        public Node get(Integer data) {
            Node now = this;
            if (now.data == data){
                return now;
            }else{
                if (now.left != null){
                    Node left = now.left.get(data);
                    if (left != null){
                        return left;
                    }
                }
                if (now.right != null){
                    Node right = now.right.get(data);
                    if (right != null){
                        return right;
                    }
                }
            }
            return null;
        }

Delete

删除操作是二叉搜索树里最复杂的了,根据删除节点的不同需要进行调整,分类有以下几类:

  • 叶子节点:叶子节点是左右节点属性都没有的节点,这种的可以直接删除
  • 单向非叶子节点:单向非叶子节点代表左右节点只有一个节点存在,这种的直接将指向删除节点的指针指向子节点即可
  • 双向非叶子节点:如果删除节点的左右节点都存在,这种的是最复杂的,因为如果删除这种节点需要对子节点进行挪移,
    找到左节点的最右节点进行替换现在删除节点的位置,之前节点位置删除。

删除代码:

        public Node delete(Node parrent, Integer data) {
            if (this != null){
                if (this.data == data){
                    if (this.left == null && this.right == null){
                        if (parrent.left != null && parrent.left.data == data){
                            parrent.left = null;
                        }else {
                            parrent.right = null;
                        }
                    }else if(this.left != null && this.right == null){
                        parrent.left = this.left;
                    }else if(this.left == null && this.right != null){
                        parrent.right = this.right;
                    }else{
                        Node node = this.left.getRightNode(this.left);
                        node.left = this.left;
                        node.right = this.right;
                        if (parrent.left != null && parrent.left.data == data){
                            parrent.left = node;
                        }else {
                            parrent.right = node;
                        }
                    }
                }else{
                    if (data > this.data) {
                        this.right.delete(this,data);
                    } else {
                        this.left.delete(this,data);
                    }
                    return this;
                }
            }
            return null;
        }

获取最左叶子节点并删除返回

这个获取最左节点的方式我写了两种,一种是递归、一种是循环

递归方式:

        private Node getRightNode(Node node){
            if(this.right != null){
            	return this.right.getRightNode(this);
            }
            node.right = null;
            return this;
        }

循环方式:

        private Node getRightNode(Node node){
            Node now = this;
            Node buffer = this;
            while(now.right != null){
                buffer = now;
                now = now.right;
            }
            buffer.right = null;
            return now;
        }

验证

往树结构内写入部分数据并删除其中节点,查看输出内容是否对应。

代码如下:

    public static void main(String[] args) {
        OrdinaryBinaryTree tree = new OrdinaryBinaryTree();
        tree.add(4);tree.add(7);tree.add(8);tree.add(2);
        tree.add(-1);tree.add(3);tree.add(0);tree.add(11);tree.add(14);tree.add(21);tree.add(9);
        tree.print();
        tree.delete(2);
        tree.print();
    }

结果:

在这里插入图片描述

图形化结构:原始数据

删除钱

图形化结构:删除后结构

在这里插入图片描述

相关文章:

  • 高通WLAN框架学习(36)-- ACS(Auto Channel Selection)自动信道选择
  • 程序流程控制(Java)
  • 分布式事务seata入门
  • 深度神经网络训练
  • 盒模型小知识点
  • Hbase-9-HBase操作-过滤器
  • matlab gui编程教程,matlab如何使用gui
  • win10如何禁止CDR软件访问网络的设置方法教程
  • u2 尚硅谷--Vue 脚手架
  • STM32使用库函数点灯实验
  • C# 学习笔记1 - 输入输出
  • 替代STM32的GD32,替代KEIL的Eclipse配置---连载3
  • 贪心算法及其简单习题
  • java特殊数据结构:栈Stack
  • 基于APB与I2C的多主多从架构设计
  • Google 是如何开发 Web 框架的
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • CSS 提示工具(Tooltip)
  • DataBase in Android
  • golang 发送GET和POST示例
  • HTTP请求重发
  • 不上全站https的网站你们就等着被恶心死吧
  • 分类模型——Logistics Regression
  • 构建工具 - 收藏集 - 掘金
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 树莓派用上kodexplorer也能玩成私有网盘
  • (pytorch进阶之路)扩散概率模型
  • (Ruby)Ubuntu12.04安装Rails环境
  • (windows2012共享文件夹和防火墙设置
  • (初研) Sentence-embedding fine-tune notebook
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (七)Knockout 创建自定义绑定
  • (十八)三元表达式和列表解析
  • (算法)求1到1亿间的质数或素数
  • (五)MySQL的备份及恢复
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net 验证控件和javaScript的冲突问题
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET单元测试
  • .net反混淆脱壳工具de4dot的使用
  • .net经典笔试题
  • .NET中使用Redis (二)
  • /run/containerd/containerd.sock connect: connection refused
  • @ 代码随想录算法训练营第8周(C语言)|Day57(动态规划)
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [20150707]外部表与rowid.txt
  • [Asp.net mvc]国际化
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [BJDCTF 2020]easy_md5