数据结构之二分搜索树

news2024/11/18 19:47:31

       树在我们底层结构中是被广泛运用的,但是为什么会选择它却是我们需要了解的东西,接下来 让我们一起走进树的世界

请看下图:

        在我们生活中,有很多关于树的存在,比如电脑中的磁盘(C D盘),在文章中写的目录都是树的一种的体现,接下来让你们深入了解树这种的数据结构

二分查找树

特点

1.动态数据结构(不需要动态扩容)

2.具有唯一的根结点

3.天然的递归结构

 满二叉树

定义:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树

                                                               以上树均不为满二叉树

假设有一个K层深的树

 

                                                            叶子节点数:2^(k-1)

                                                           总叶子结点数:2^k-1

                                                          非叶子结点数:2^(k-1)-1

                                                            树的空间复杂度:O(logn)

下面是树方法的最基本的是实现:

  //对节点进行初始化
    class Node{
        T ele;
        Node left;
        Node right;

        public Node(T ele){
            this.ele=ele;
            this.left=null;
            this.right=null;
        }
    }

    //对搜索二叉树进行初始化
    private Node root;
    private int size;
    public BinarySearchTree(){
        this.root=null;
        this.size=0;
    }
    //对外提供增加方法
    public void add(T ele){
       this.root=add(this.root,ele);
    }
    //实际调用的增加的方法
    private Node add(Node node,T ele){
        //如果node为空的话,直接在根节点进行添加
        if(node==null){
            Node addNode=new Node(ele);
            this.size++;
            return addNode;
        }
        //若添加的节点与对应的根节点进行比较,小于的话直接挂接在左子树上
        if(ele.compareTo(node.ele)<0){
            node.left=add(node.left,ele);
            //大于等于挂接在右子数上
        }else{
            node.right=add(node.right,ele);
        }
        return node;
    }

    //对外提供的查询方法
    public Boolean search(T ele){
       return search(this.root,ele);
    }
    //实际调用的方法
    private Boolean search(Node node,T ele){
        if(node==null){
            return false;
        }
        if(ele.compareTo(node.ele)>0){
             return search(node.right,ele);
        }else if(ele.compareTo(node.ele)<0){
            return search(node.left,ele);
        }else{
            return true;
        }
    }

    //中序遍历(DFS)
    public void mtraversal(){
        middleTraversal(this.root);
    }

    private void middleTraversal(Node node){
        if(node==null){
            return;
        }
        middleTraversal(node.left);
        System.out.println(node.ele);
        middleTraversal(node.right);
    }

    //前序遍历(DFS)
    public void btraversal(){
        beforeTraversal(this.root);
    }

    private void beforeTraversal(Node node){
        if(node==null){
            return;
        }
        System.out.println(node.ele);
        beforeTraversal(node.left);
        beforeTraversal(node.right);
    }
    //后续遍历(DFS)

    public void atraversal(){
        afterTraversal(this.root);
    }

    private void afterTraversal(Node node){
        if(node==null){
            return;
        }
        afterTraversal(node.left);
        afterTraversal(node.right);
        System.out.println(node.ele);
    }

    //层序遍历(BFS)使用队列进行保存
    public void ltraversal(){
        String sb= levelTraversal(this.root);
        System.out.println(sb);
    }
    //实际调用的层序遍历方法
    private String levelTraversal(Node node){
        //如果头结点为空,直接返回
        if(node==null){
            return null;
        }
        //创建一个队列
        Queue<Node> queue=new LinkedList<Node>();
        queue.offer(node);
        StringBuilder sb=new StringBuilder();
       //如果该节点不为空,进行遍历,输出
        while(!queue.isEmpty()){
            Node curNode=queue.poll();
            sb.append(curNode.ele+",");
            //如果左子树不为空的话,入队
            if(curNode.left!=null){
                queue.offer(curNode.left);
            }
            //如果右子树不为空的话入队
            if(curNode.right!=null){
                queue.offer(curNode.right);
            }
        }

         return sb.toString().substring(0,sb.length()-1) ;
    }

    //在二分搜索树中找到最大值(使用递归方法)
    public Optional<T> getmax(){
        if (this.root == null) {
            return Optional.empty();
        }
        Node node=getMax(this.root);
        return Optional.of(node.ele);
    }

    private Node getMax(Node node){
        //递归的终止条件
        if(node.right==null){
            return node;
        }
        //当节点不为空的时候,进行递归
        return getMax(node.right);
    }

    //在二分搜索树中找到最大值
    public Optional<T> getMax1(){
        if (this.root == null) {
            return Optional.of(null);
        }
        Node curNode=this.root;
        while(curNode.right!=null){
            curNode=curNode.right;
        }
        return Optional.of(curNode.ele);
    }

    //在二分搜索树中找到最小值(递归)
    public Optional<T> getmin(){
        if (this.root == null) {
            return Optional.empty();
        }
        Node node=getMin(this.root);
        return Optional.of(node.ele);
    }

    private Node getMin(Node node){
        //递归的终止条件
        if(node.left==null){
            return node;
        }
        //当节点不为空的时候,进行递归
        return getMin(node.left);
    }

    //在二分搜索树中找到最小值
    public Optional<T> getMin2(){
        if(this.root==null){
            return Optional.of(null);
        }
        Node curNode=this.root;
        while(curNode.left!=null){
            curNode=curNode.left;
        }
        return Optional.of(curNode.ele);
    }

    //删除树中的最大结点
    public T removeMaxNode(){
        //查找最大的结点
        Optional<T> optional=getmax();
        //判断是否存在
        if(!optional.isPresent()){
            return null;
        }
        //分析存在的情况
        this.root=removeMaxNode(this.root);
        return optional.get();
    }

    // 从以node为根的二分搜索树中删除最大的结点
    private Node removeMaxNode(Node node) {
        // 递归到底的情况
        if (node.right == null) {
            this.size--;
            // 进行删除
            return node.left;
        }
        // 递归操作
        node.right = removeMaxNode(node.right);
        return node;
    }

    //删除任意结点
    public boolean remove(T ele){
        //判断值为ele的结点在树中是否存在
        boolean result=search(ele);
        if(result){
            //使用递归的方式进行是删除
            this.root=remove(this.root,ele);
        }
        return result;
    }
    //以node为根的二分搜索树中删除结点值为ele的结点
    private Node remove(Node node,T ele){
        //递归终止条件
        if(node.ele.compareTo(ele)==0){
            this.size--;
            if(node.left==null){
                return node.right;
            }else if(node.right==null){
                return node.left;
            }else{
                //先从删除结点的左子树中找到最大
                Node preNode=getMax(node.left);
                //从左子树删除最大的元素
                Node rightNodeRoot=removeMaxNode(node.left);
                //进行挂接
                preNode.right=node.right;
                preNode.left=rightNodeRoot;
                this.size++;
                return preNode;

            }
        }
        if(ele.compareTo(node.ele)>0){
            node.right=remove(node.right,ele);
        }else{
            node.left=remove(node.left,ele);
        }
        return node;
    }

    @Override
    public String toString() {
        return "当前节点的个数为:"+this.size;
    }

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

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

相关文章

LangChain与大型语言模型(LLMs)应用基础教程:记忆力组件

如果您还没有看过我之前写的两篇博客&#xff0c;请先看一下&#xff0c;这样有助于对本文的理解&#xff1a; LangChain与大型语言模型(LLMs)应用基础教程:Prompt模板 LangChain与大型语言模型(LLMs)应用基础教程:信息抽取 LangChain与大型语言模型(LLMs)应用基础教程:角色…

在线甘特图制作教程

在线甘特图制作教程 很多的甘特图工具都是需要下载到本地&#xff0c;并且做好了之后也不方便分享给别人。给大家分享一个在线的甘特图制作工具 不需要登录注册 知竹甘特图 https://www.yxsss.com/ 打开知竹甘特图 https://www.yxsss.com/gatt/3b7d1ecb7211b9473e7d1ecb72 …

015:Mapbox GL绘制修改多边形,实时更新面积

第015个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中添加draw组件,绘制多边形,编辑多边形,实时显示面积值。这里使用turf来计算面积值。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共92行)安装…

ASP.NET Core MVC 从入门到精通之wwwroot和客户端库

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

remvw布局

文章目录 rem&vw布局rem布局方式原理使用第三框架 vw布局方式原理使用 rem&vw混合布局方式vw方案案例 rem&vw布局 rem布局方式 原理 rem是相对于根元素&#xff08;html元素&#xff09;的字体大小来计算的&#xff0c;因此可以根据不同的屏幕尺寸和设备类型自动…

EF Core入门

文章目录 前言一、EF Core环境搭建二、基本的增删改查1.增加数据2.查询数据3.修改数据&#xff0c;删除数据 前言 EF Core是微软官方提供的ORM框架。EF Core不仅可以操作Microsoft SQL Server、MySQL、Oracle、PostgreSQL等数据库&#xff0c;而且可以操作Azure Cosmos DB等No…

【让你惊呼的“神器”,ChatGPT inside】

让你惊呼的“神器”&#xff0c;ChatGPT inside ChatGPT 的横空出世&#xff0c;已经搅动了整个科技圈。而它给自然语言处理领域带来的革命性变革&#xff0c;也为很多初创公司和开发者打开了新世界的大门。 在过去&#xff0c;自然语言处理技术通常只被各大科技巨头藏私&…

玩机搞机----root面具的安装 更新 隐藏root 德尔塔面具等等综合解析

目前的机型都是root面具&#xff0c;今天的帖子主要分析下面具的一些使用常识。一般面具如何使用一参考我前面的帖子。基本步骤都是解锁bl---修补boot---刷入boot----安装面具apk。但目前很多app会检测系统root&#xff0c;对于有些敏感类软件例如银行等等然后会检测当前系统ro…

C/C++每日一练(20230423)

目录 1. 多组输入求和 ※ 2. 螺旋矩阵 II &#x1f31f;&#x1f31f; 3. 路径交叉 &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 多组…

用golang实现traceroute

Traceroute 概念 traceroute是一种网络诊断工具&#xff0c;通过traceroute可以诊断出本机到目的地IP之间的路由情况&#xff0c;例如路由跳数、延迟、是否可达等信息。该工具在linux环境下的命令是traceroute或者tracepath&#xff0c;在windows下命令是tracert。 工作原理…

动态路由四大天王:OSPF、RIP、IS-IS、BGP,收藏这篇文章足以!

在计算机网络中&#xff0c;OSPF、RIP、IS-IS、BGP 都是常见的路由协议。它们分别具有不同的特点和适用场景。本文将对这四种路由协议进行对比&#xff0c;以帮助读者更好地了解它们的优缺点和适用范围。 OSPF OSPF&#xff08;Open Shortest Path First&#xff09;是一种链路…

中文编程最高境界,不用编程,会用excel就会用,香不香?

一直以来&#xff0c;关于中文编程的争议从未消停过。现如今&#xff0c;中文编程发展又是如何&#xff1f; ★为了实现中文编程&#xff0c;从未停下脚步 我们知道&#xff0c;中国人一直以来为了实现中文编程付出了不懈的努力&#xff0c;前前后后研发了几十种中文编程语言。…

JavaSE补充 | 了解数据结构与常用集合的源码分析

目录 一&#xff1a;数据结构 1. 数据结构剖析 1.1 研究对象一&#xff1a;数据间逻辑关系 1.2 研究对象二&#xff1a;数据的存储结构&#xff08;或物理结构&#xff09; 1.3 研究对象三&#xff1a;运算结构 2. 常见存储结构之&#xff1a;数组 3. 常见存储结构之&am…

奇葩的new Date()

大家平时在开发的时候有没被new Date()折磨过&#xff1f;就是它的诸多怪异的设定让你每每用的时候&#xff0c;都可能不小心踩坑。造成程序意外出错&#xff0c;却一下子找不到问题出处&#xff0c;那叫一个烦透了…… 下面&#xff0c;我就列举它的“四宗罪”及应用思考 可恶…

微前端运行时

目录 微前端运行时基于 SPA 的微前端架构应用生命周期 微前端运行时 谈到微前端绕不开的话题就是为什么不适用 iframe 作为承载微前端子应用的容器&#xff0c;其实从浏览器原生的方案来说&#xff0c;iframe 不从体验角度上来看几乎是最可靠的微前端方案了&#xff0c;主应用…

关于FPV图传系统时延讨论

关于FPV图传系统时延讨论 1. 源由2. 时延测试方法3. 时延测试资料4. 关于模拟图传5. 关于FPV时延感受5.1 静态时延5.2 动态时延 6. 参考资料7. 附录 DJI 图传系统 1. 源由 视频图传系统最重要的几个指标&#xff1a; 分辨率视角帧率时延传输距离 目前高清图传主要规则&#…

【Cartopy基础入门】如何丝滑的加载Geojson数据

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 Cartopy基础入门 【Cartopy基础入门】Cartopy的安装 【Cartopy基础入门】如何丝滑的加载Geojson数据 文章目录 Cartopy基础入门一、Geojson数据来源二…

C语言 非本地跳转 实现native层TryCatch

前言 最近研究native hook的技术&#xff0c;了解到了这个非本地跳转&#xff0c;本文就是介绍他&#xff0c;对于解决native crash非常有用。 非本地跳转介绍 C语言的本地跳转是指goto、break、continue等语句&#xff0c;但是这个语句最大局限就是只能实现函数内部的跳转。…

Day3 自学Pytorch 数据集 torchvision.transforms类&torchvision.datasets.ImageFolder类

1.torchvision.transforms类 可调用的函数列表https://pytorch.org/vision/stable/transforms.html 介绍几个常用的函数&#xff1a; ① transforms.Resize(&#xff09; 将图像转换成目标大小 参数列表&#xff1a; size (sequence or int)&#xff1a; &#xff08;h,w&a…

Scala 中的 List 列表详解

目录 一、不可变长的List列表 1.List列表的声明与遍历 2.List列表的map、flatMap函数 3.List列表的filter过滤函数 4.List列表的count计数函数 二、可变长的List列表 1.可变长List声明 2.可变长List的添加方法 三、List列表其余的方法与函数 一、不可变长的List列表 …