18 二叉树

news2024/11/15 8:03:59

文章目录

  • 1 为什么需要树这种数据结构
  • 2 树示意图
  • 3 二叉树的概念
  • 4 二叉树的遍历
  • 5 二叉树的遍历的代码实现
  • 6 二叉树的遍历查找的代码实现

1 为什么需要树这种数据结构

1) 数组存储方式的分析
优点:通过下标方式访问元素,速度快。对于有序数组,还可使用二分查找提高检索速度。
缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动,效率较低 [示意图]画出操作示意图:

在这里插入图片描述
2) 链式存储方式的分析
优点:在一定程度上对数组存储方式有优化(比如:插入一个数值节点,只需要将插入节点,链接到链表中即可,删除效率也很好)。
缺点:在进行检索时,效率仍然较低,比如(检索某个值,需要从头节点开始遍历) 【示意图】操作示意图:

在这里插入图片描述
3) 树存储方式的分析
能提高数据存储,读取的效率, 比如利用 二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。【示意图,后面详讲】
案例: [7, 3, 10, 1, 5, 9, 12]

在这里插入图片描述

2 树示意图

在这里插入图片描述
在这里插入图片描述

3 二叉树的概念

1) 树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树。
2) 二叉树的子节点分为左节点和右节点
3) 示意图

在这里插入图片描述
4) 如果该二叉树的所有叶子节点都在最后一层,并且结点总数= 2^n -1 , n 为层数,则我们称为满二叉树。

在这里插入图片描述
5) 如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树

在这里插入图片描述

4 二叉树的遍历

1) 前序遍历: 先输出父节点,再遍历左子树和右子树
2) 中序遍历: 先遍历左子树,再输出父节点,再遍历右子树
3) 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点
4) 小结: 看输出父节点的顺序,就确定是前序,中序还是后序

在这里插入图片描述

5 二叉树的遍历的代码实现

package tree;

/**
 * @author Andy
 * @email andy.gsq@qq.com
 * @date 2023/2/18 21:36:06
 * @desc 二叉树的演示
 */

public class BinaryTreeDemo {
    public static void main(String[] args) {
        //先需要创建一颗二叉树
        BinaryTree binaryTree = new BinaryTree();
        //创建需要的结点
        HeroNode root = new HeroNode(1, "宋江");
        HeroNode node2 = new HeroNode(2, "吴用");
        HeroNode node3 = new HeroNode(3, "卢俊义");
        HeroNode node4 = new HeroNode(4, "林冲");
        HeroNode node5 = new HeroNode(5, "关胜");
        //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);
        //测试
        System.out.println("前序遍历"); // 1,2,3,5,4
        binaryTree.preOrder();
        //测试
        System.out.println("中序遍历");
        binaryTree.infixOrder(); // 2,1,5,3,4
        //
        System.out.println("后序遍历");
        binaryTree.postOrder(); // 2,5,4,3,1
    }
}

class BinaryTree {
    private HeroNode root;

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public BinaryTree() {
    }

    public BinaryTree(HeroNode root) {
        this.root = root;
    }

    //前序遍历
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

    //中序遍历
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

    //后序遍历
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

}

class HeroNode {
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;

    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode[no=" + no + ", name='" + name + "]";
    }

    /**
     * 前序遍历
     */
    public void preOrder() {
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    /**
     * 中序遍历
     */
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    /**
     * 后序遍历
     */
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }

        if (this.right != null) {
            this.right.postOrder();
        }
        System.out.println(this);
    }
}

6 二叉树的遍历查找的代码实现

package tree;

/**
 * @author Andy
 * @email andy.gsq@qq.com
 * @date 2023/2/18 21:36:06
 * @desc 二叉树的演示
 */

public class BinaryTreeDemo {
    public static void main(String[] args) {
        //先需要创建一颗二叉树
        BinaryTree binaryTree = new BinaryTree();
        //创建需要的结点
        HeroNode root = new HeroNode(1, "宋江");
        HeroNode node2 = new HeroNode(2, "吴用");
        HeroNode node3 = new HeroNode(3, "卢俊义");
        HeroNode node4 = new HeroNode(4, "林冲");
        HeroNode node5 = new HeroNode(5, "关胜");
        //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);
        //测试
        System.out.println("前序遍历"); // 1,2,3,5,4
        binaryTree.preOrder();
        //测试
        System.out.println("中序遍历");
        binaryTree.infixOrder(); // 2,1,5,3,4
        //
        System.out.println("后序遍历");
        binaryTree.postOrder(); // 2,5,4,3,1


        //前序遍历
        //前序遍历的次数 :4
        System.out.println("前序遍历方式~~~");
        HeroNode resNode1 = binaryTree.preOrderSearch(5);
        if (resNode1 != null) {
            System.out.printf("找到了,信息为 no=%d name=%s\n", resNode1.getNo(), resNode1.getName());
        } else {
            System.out.printf("没有找到 no = %d 的英雄\n", 5);
        }

        //中序遍历查找
        //中序遍历 3 次
        System.out.println("中序遍历方式~~~");
        HeroNode resNode2 = binaryTree.infixOrderSearch(5);
        if (resNode2 != null) {
            System.out.printf("找到了,信息为 no=%d name=%s\n", resNode2.getNo(), resNode2.getName());
        } else {
            System.out.printf("没有找到 no = %d 的英雄\n", 5);
        }

        //后序遍历查找
        //后序遍历查找的次数 2 次
        System.out.println("后序遍历方式~~~");
        HeroNode resNode3 = binaryTree.postOrderSearch(5);
        if (resNode3 != null) {
            System.out.printf("找到了,信息为 no=%d name=%s\n", resNode3.getNo(), resNode3.getName());
        } else {
            System.out.printf("没有找到 no = %d 的英雄\n", 5);
        }
    }
}

class BinaryTree {
    private HeroNode root;

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public BinaryTree() {
    }

    public BinaryTree(HeroNode root) {
        this.root = root;
    }

    //前序遍历
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

    //中序遍历
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

    //后序遍历
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            System.out.println("二叉树为空,无法遍历");
        }
    }

    //前序遍历查找
    public HeroNode preOrderSearch(int no) {
        if (root != null) {
            return root.preOrderSearch(no);
        } else {
            return null;
        }
    }

    //中序遍历查找
    public HeroNode infixOrderSearch(int no) {
        if (root != null) {
            return root.infixOrderSearch(no);
        } else {
            return null;
        }
    }

    //后序遍历查找
    public HeroNode postOrderSearch(int no) {
        if (root != null) {
            return this.root.postOrderSearch(no);
        } else {
            return null;
        }
    }

}

class HeroNode {
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;

    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode[no=" + no + ", name='" + name + "]";
    }

    /**
     * 前序遍历
     */
    public void preOrder() {
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    /**
     * 中序遍历
     */
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    /**
     * 后序遍历
     */
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }

        if (this.right != null) {
            this.right.postOrder();
        }
        System.out.println(this);
    }

    /**
     * 前序遍历查找
     *
     * @param no 查找 no
     * @return 如果找到就返回该 Node ,如果没有找到返回 null
     */
    public HeroNode preOrderSearch(int no) {
        System.out.println("进入前序遍历");
        if (this.no == no)
            return this;
        //1.则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
        //2.如果左递归前序查找,找到结点,则返回
        HeroNode resNode = null;
        if (this.left != null) {
            resNode = this.left.preOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;//说明我们左子树找到
        }

        //1.左递归前序查找,找到结点,则返回,否继续判断,
        //2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找

        if (this.right != null) {
            resNode = this.right.preOrderSearch(no);
        }

        return resNode;
    }

    /**
     * 前序遍历查找
     *
     * @param no 查找 no
     * @return 如果找到就返回该 Node ,如果没有找到返回 null
     */
    public HeroNode infixOrderSearch(int no) {
        System.out.println("进入前序遍历");

        //1.则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
        //2.如果左递归前序查找,找到结点,则返回
        HeroNode resNode = null;
        if (this.left != null) {
            resNode = this.left.infixOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;//说明我们左子树找到
        }

        if (this.no == no)
            return this;

        //1.左递归前序查找,找到结点,则返回,否继续判断,
        //2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找

        if (this.right != null) {
            resNode = this.right.infixOrderSearch(no);
        }

        return resNode;
    }

    //后序遍历查找
    public HeroNode postOrderSearch(int no) {
        //判断当前结点的左子节点是否为空,如果不为空,则递归后序查找
        HeroNode resNode = null;
        if (this.left != null) {
            resNode = this.left.postOrderSearch(no);
        }
        if (resNode != null) {//说明在左子树找到
            return resNode;
        }
        //如果左子树没有找到,则向右子树递归进行后序遍历查找
        if (this.right != null) {
            resNode = this.right.postOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;
        }
        System.out.println("进入后序查找");
        //如果左右子树都没有找到,就比较当前结点是不是
        if (this.no == no) {
            return this;
        }
        return resNode;
    }
}

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

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

相关文章

【Linux】进程状态

文章目录1. 阻塞1. 举例2. 为什么要阻塞?3.操作系统层面上如何理解进程等待某种资源就绪呢?资源进程4. 总结2.挂起3.Linux进程状态1. R状态进程只要是R状态,就一定是在CPU运行吗?证明当前进程运行状态生成程序查看进程2. S休眠状态…

New和Malloc的使用及其差异

1,new的使用关于new的定义:new其实就是告诉计算机开辟一段新的空间,但是和一般的声明不同的是,new开辟的空间在堆上,而一般声明的变量存放在栈上。通常来说,当在局部函数中new出一段新的空间,该…

Go项目(三)

文章目录用户微服务表结构查表web 服务跨域问题图形验证码短信用户注册服务中心注册 grpc 服务动态获取端口负载均衡配置中心启动项目小结用户微服务 作为系统的第一个微服务,开发的技术点前面已经了解了一遍,虽有待补充,但急需实战这里主要…

pytorch离线快速安装

1.pytorch官网查看cuda版本对应的torch和torchvisionde 版本(ncvv -V,nvidia-sim查看cuda对应的版本) 2.离线下载对应版本,网址https://download.pytorch.org/whl/torch_stable.html 我下载的: cu113/torch-1.12.0%2Bcu113-cp37-cp37m-win_…

基于python的一款数据处理工具pandas

在python处理数据的时候,都免不了用pandas做数据处理。在数据处理时,都免不了用数据筛选来提取自己想要的数据,咱们今天就讲讲pandas的条件筛选。安装库建议做数据分析的酱友们安装anaconda3,这个包几乎包括了数据分析用的所需要的…

【博客623】Prometheus一条告警的触发流程与等待时间

Prometheus一条告警的触发流程与等待时间 1、与告警等待时间相关的参数 prometheus.yml global:# 数据采集间隔scrape_interval: 15s # 评估告警周期evaluation_interval: 15s # 数据采集超时时间默认10s# scrape_timeoutalertmanager.yml # route标记:告警…

Python urllib

Python urllib Python urllib 库用于操作网页 URL,并对网页的内容进行抓取处理。 本文主要介绍 Python3 的 urllib。 urllib 包 包含以下几个模块: urllib.request - 打开和读取 URL。urllib.error - 包含 urllib.request 抛出的异常。urllib.parse …

剑指Offer专项突击版题解八

71.按权重生成随机数 思考:说到平均的生成随机数,想到了水塘抽样法和彩票调度法。 水塘抽样算法适合于样本不确定,乃至于是变化的,每个样本的概率是一样的。 // 样本nums[],每个元素的被抽到的概率是一样的 index : 0 for i : 1;…

Kubernetes03:kubernetes 功能和架构

2.1 概述 Kubernetes 是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过 Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中,会将组成应用的容 器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环…

时序预测 | Python实现TCN时间卷积神经网络时间序列预测

时序预测 | Python实现TCN时间卷积神经网络时间序列预测 目录 时序预测 | Python实现TCN时间卷积神经网络时间序列预测预测效果基本介绍环境准备模型描述程序设计学习小结参考资料预测效果 基本介绍 递归神经网络 (RNN),尤其是 LSTM,非常适合时间序列处理。 作为研究相关技术…

生成模型技术发展过程

生成模型生成模型和判别模型的差异生成模型的目标是在给定了数据集D,并且假设这个数据集的底层分布(underlying distribution)是Pdata,我们希望够近似出这个数据分布。如果我们能够学习到一个好的生成模型,我们就能用这个生成模型为下游任务做…

【项目立项管理】

项目立项管理 很杂,可以根据左边的列表查看自己不会的 。。。 立项管理主要是解决项目的组织战略符合性问题 开发所需的成本和资源属于经济可行性 承建方组织资源和项目的匹配程度 内部立项目的: 为项目进行资源分配,确定项目绩效目标&am…

字节二面:10Wqps超高流量系统,如何设计?

超高流量系统设计思路 前言 在40岁老架构师 尼恩的**读者交流群(50)**中,大流量、高并发的面试题是一个非常、非常高频的交流话题。最近,有小伙伴面试字节时,遇到一个面试题: 10Wqps超高流量系统,该如何设计&#xf…

湿度敏感性等级(MSL)

趁着周末得空,也有意愿,赶紧把之前一直想写的这个主题完成了。 湿度敏感性等级,相信大部分人还是比较陌生的。 湿度敏感性等级:MSL,Moisture sensitivity level 之所以有这个等级,大概是因为以下原因&a…

软考高级-信息系统管理师之进度管理(最新版)

项目进度管理 项目进度管理1概述2项目进度管理过程2.1规划进度管理1、规划项目进度管理目的2、规划进度管理:输入3、规划进度管理:输出2.2定义活动1、为了更好地规划项目2、定义活动过程就是3、定义活动:输入4、定义活动:输出2.3排列活动顺序1、排列活动顺序2、排列活动顺序:输…

19 顺序存储二叉树

文章目录1 顺序存储二叉树的概念1 顺序存储二叉树的概念 从数据存储来看,数组存储方式和树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组,看右面的示意图。 要求: 1) 右图的二叉树的结点,要求以数…

Git常用命令以及如何在IDEA中使用Git

前言Git是一个分布式版本控制工具,主要用于管理开发过程中的源代码文件(Java类、xml文件、html页面等)。Git在管理文件过程中会记录日志,方便回退到历史版本;Git存在分支的概念,一个项目可以有多个分支&…

linux014之进程和服务管理

linux中的进程管理: 查看进程命令: ps :查看应用级别的进程 ps -e: 查看系统应用级的进程 ps -ef :显示进程的全部信息(这个命令经常用) ps -ef|grep 关键字: 查看带有关键字的进程 关闭进程命令&#xff1…

win11+pytorch1.7.0+python3.8(也可以是python3.7)+cuda11.0

win11pytorch1.7.0python3.8cuda11.0写在最前面一. 软件配备二. 创建虚拟环境2.1 创建环境名称,并选择‘y’2.2.进入虚拟环境三. 安装pytorch四. 安装虚拟环境下的notebook4.1 安装ipykernel,并选择‘y’,直至安装完成4.2 将环境名注册到note…

安全—09day

XSS1. XSS的原理2. Xss漏洞分类2.1 反射性xss2.2 存储型XSS2.3 基于DOM的 XSS2.4 XSS漏洞的危害3. XSS的各种bypass技巧4. 从 XSS Payload 学习浏览器解码5. 浏览器解析机制5.1 HTML中有五类元素:5.2 五类元素的区别1. XSS的原理 恶意攻击者往Web页面里插入恶意Scr…