二叉树代码

2023-11-11

1.普通二叉树的构建

构建结点以及搜索与删除的方法

public class Node {

    private int no;
    private String name;
    private Node left;
    private Node right;
    private Node parent;

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

    public int getNo() {
        return no;
    }

    public Node getParent() {
        return parent;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

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

    public String getName() {
        return name;
    }

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

    public Node getLeft() {
        return left;
    }

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

    public Node getRight() {
        return right;
    }

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

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", left=" + left +
                ", right=" + right +
                '}';
    }

    // 前序遍历
    // 先输出父结点,再遍历左子树和右子树
    public void preOrder(){

        System.out.println(this);
        if (this.left != null){
            this.left.preOrder();
        }

        if (this.right != null){
            this.right.preOrder();
        }
    }

    // 中序遍历
    // 先遍历左子树,再遍历父结点,再遍历右子树
    public void midOrder(){
        if (this.left != null){
            this.left.midOrder();
        }

        System.out.println(this);

        if (this.right != null){
            this.right.midOrder();
        }
    }

    // 后序遍历 左右中
    public void postOrder(){

        if (this.left != null){
            this.left.preOrder();
        }

        if (this.right != null){
            this.right.preOrder();
        }

        System.out.println(this);
    }


    // 前序遍历查找
    public Node preSearch(int no){


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

        if (this.left != null){
            return this.left.preSearch(no);
        }

        if (this.right != null){
            return this.right.preSearch(no);
        }

        return null;
    }

    // 前序遍历查找
    public Node midSearch(int no){



        if (this.left != null){
            return this.left.midSearch(no);
        }

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


        if (this.right != null){
            return this.right.midSearch(no);
        }

        return null;
    }

    // 前序遍历查找
    public Node postSearch(int no){

        if (this.left != null){
            return this.left.postSearch(no);
        }

        if (this.right != null){
            return this.right.postSearch(no);
        }

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

        return null;
    }

    // 删除结点的两种情况
    // 1. 删除的是叶子结点
    // 2. 删除的结点是子树,非叶子结点
    // 3. 单向二叉树
    public void delete(int no){

        /**注意:
         * 1、二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除,而不能去判断当前这个结点是不是需要删除结点
         * 2、如果当前结点左子结点不为空,并且左子结点就是需要删除的结点,则将this.left = null,返回即可
         * 3、如果当前结点右子结点不为空,并且右子结点就是需要删除的结点,就将this.right = null,返回即可
         * 4、如果2,3步没有执行,那么需要向左子树进行递归删除
         * 5、如果第4步也没有删除结点,则向右子树进行递归删除
         **/

        if (this.left != null && this.left.no == no){
            this.left = null;
            return;
        }

        if (this.right != null && this.right.no == no){
            this.right = null;
            return;
        }

        if (this.left != null){
            this.left.delete(no);
        }

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

    }
}

构建二叉树类并实现删除搜索的方法

public class BinaryTree {

    private Node root;

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

    // 前序遍历
    public void preOrder(){

        if (root != null){
            root.preOrder();
        }else {
            System.out.println("二叉树为空");
        }
    }

    // 中序遍历
    public void midOrder(){

        if (root != null){
            root.midOrder();
        }else {
            System.out.println("二叉树为空");
        }
    }

    // 后序遍历
    public void postOrder(){

        if (root != null){
            root.postOrder();
        }else {
            System.out.println("二叉树为空");
        }
    }

    public Node preSearchById(int no){

        if (root != null){
            return root.preSearch(no);
        }else {
            System.out.println("未找到");
            return null;
        }
    }

    public Node midSearchById(int no){

        if (root != null){
            return root.midSearch(no);
        }else {
            System.out.println("未找到");
            return null;
        }
    }

    public Node postSearchById(int no){

        if (root != null){
            return root.postSearch(no);
        }else {
            System.out.println("未找到");
            return null;
        }
    }

    public void delNode(int no){

        if (root != null){
            if (root.getNo() == no){
                root = null;
            }else {
                root.delete(no);
            }
        }else {
            System.out.println("未找到");
        }


    }
}

2.线索二叉树

将数列[1,3,6,8,10,14] 构建成一颗二叉树
![在这里插入图片描述](https://img-blog.csdnimg.cn/b103c25d371244bc8db0be82d8fad944.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAYmVjb2Vt,size_20,color_FFFFFF,t_70,g_se,x_16
问题分析:
1、当我们对上述二叉树进行中序遍历时,数列为[8,3,10,1,6,14] 8是3的前驱,10是3的后继
2、6,8,10,14这几个结点左右指针并没有很好的利用上。
3、如果考虑能够让每个结点充分利用左右指针指向自己的前后结点怎么去解决呢
这时只能选择使用线索二叉树
4、一个结点的前一个结点,称之为前驱结点,一个结点后一个结点称之为后继结点。

线索二叉树介绍
在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化
在这里插入图片描述
对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树。(前驱和后继和选择哪种遍历方法有关)
这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。

HeroNode 构建二叉树

public class HeroNode {

    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;
    private HeroNode parent;

    // 如果是0,表示指向的是左子树, 1表示指向前驱
    private int noLeft;

    // 如果是0,表示指向的是右子树, 1表示指向后继
    private int noRight;

    public HeroNode() {
    }

    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;
    }

    public int getNoLeft() {
        return noLeft;
    }

    public void setNoLeft(int noLeft) {
        this.noLeft = noLeft;
    }

    public int getNoRight() {
        return noRight;
    }

    public void setNoRight(int noRight) {
        this.noRight = noRight;
    }

    public HeroNode getParent() {
        return parent;
    }

    public void setParent(HeroNode parent) {
        this.parent = parent;
    }

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

    // 删除结点
    // 删除的可能是一个叶子结点,也可能是非叶子结点
    public void delete(int no){

        if (this.left != null && this.left.no == no){
            this.left = null;
            return;
        }

        if (this.right != null && this.right.no == no){
            this.right = null;
            return;
        }

        // 判断,防止异常
        if (this.left != null){
            this.left.delete(no);
        }

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

    }

    // 前序遍历
    public void preSearch(){

        System.out.println(this);

        if (this.left != null){
            this.left.preSearch();
        }

        if (this.right != null){
            this.right.preSearch();
        }
    }

    // 根据编号查找
    public HeroNode preSearchByNo(int no){

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

        HeroNode temp = null;

        if (this.left != null){
            temp =  this.left.preSearchByNo(no);
        }

        if (temp != null){
            return temp;
        }

        if (this.right != null){
            temp = this.right.preSearchByNo(no);
        }

        return temp;
    }

    // 中序遍历
    public void midSearch(){


        if (this.left != null){
            this.left.midSearch();
        }

        System.out.println(this);

        if (this.right != null){
            this.right.midSearch();
        }
    }

    // 后序遍历
    public void postSearch(){


        if (this.left != null){
            this.left.postSearch();
        }

        if (this.right != null){
            this.right.postSearch();
        }

        System.out.println(this);
    }

}

构建线索二叉树并进行搜索

public class ClueBinaryTree {

    private HeroNode root;

    // 当前结点的前驱结点的指针
    private HeroNode pre; // 前驱


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

    // 非线索化二叉树转线索化二叉树
    public void cluePreNode(){
        this.cluePreNode(root);
    }

    public void clueNode(){
        this.clueNode(root);
    }




    /*
      把普通二叉树转线索化二叉树
   */
    public void cluePreNode(HeroNode node){

        // 中左右
        if (node == null){
            return;
        }

        if (node.getLeft() == null){
            node.setLeft(pre);
            node.setNoLeft(1);
        }

        if (pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setNoRight(1);
        }

        pre = node;

        // 如果左子树没有线索化,那么线索化左子树
        if (node.getNoLeft() != 1){
            cluePreNode(node.getLeft());
        }

        //如果右子树没有线索化,那么线索化左子树
        if (node.getNoRight() != 1){
            cluePreNode(node.getRight());
        }

    }

    /*
    把普通二叉树转线索化二叉树
 */
    public void cluePostNode(HeroNode node){

        if (node == null){
            return;
        }

        cluePreNode(node.getLeft());

        cluePreNode(node.getRight());

        if (node.getLeft() == null){
            node.setLeft(pre);
            node.setNoLeft(1);
        }

        if (pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setNoRight(1);
        }

        pre = node;

    }

    /*
       把普通二叉树转线索化二叉树
    */
    public void clueNode(HeroNode node){

        if (node == null){
            return;
        }

        clueNode(node.getLeft());


        if (node.getLeft() == null){
            node.setLeft(pre);
            node.setNoLeft(1);
        }

        if (pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setNoRight(1);
        }

        pre = node;

        clueNode(node.getRight());
    }

    // 遍历线索化的二叉树
    public void cluePreList(){

        // 临时结点
        HeroNode node = root;

        while (node != null){

            // 左中右
            // 向左查找头结点
            // node.getNoLeft() == 0没有连接前驱的就不是最后
            System.out.println(node);

            while (node.getNoLeft() == 0){
                node = node.getLeft();
            }

            // 查看有没有连接后继,连接了后继就可以通过这个寻找到后继,并将指针上移至后继处
            while(node.getNoRight() == 1){
                node = node.getRight();
                System.out.println(node);
            }

            node = node.getRight();
        }
    }


    // 遍历线索化的二叉树
    public void clueList(){

        // 临时结点
        HeroNode node = root;

        while (node != null){

            // 左中右
            // 向左查找头结点
            // node.getNoLeft() == 0 没有连接前驱的就不是最后
            while (node.getNoLeft() == 0){
                node = node.getLeft();
            }

            System.out.println(node);

            // 查看有没有连接后继,连接了后继就可以通过这个寻找到后继,并将指针上移至后继处
            while(node.getNoRight() == 1){
                node = node.getRight();
                System.out.println(node);
            }

            node = node.getRight();
        }
    }

}

3.顺序存储二叉树

二叉树的顺序存储就是用一组连续的存储单元(数组)存放二又树中的结点元素,一般按照二叉树结点自上向下、自左向右的顺序存储。
在这里插入图片描述顺序存储二叉树特点:
1、顺序二叉树通常只考虑完全二叉树
2、第n个元素的左子结点编号为2n+1 比如元素为6的那个结点,它是第3个元素,则其左子结点编号为 2 * 3 + 1 = 7
3、第n个元素的右子结点编号为2
n+2
4、第n个元素的父结点为(n-1)/2
5、n表示二叉树中第几个元素,按编号从0开始

public class ArrayBinaryTree {

    private final int[] arrays;

    public ArrayBinaryTree(int[] arrays){
        this.arrays = arrays;
    }


    // 前序遍历顺序存储二叉树
    // 从编号index开始遍历
    public void preSelect(int index){

        if (this.arrays == null || arrays.length == 0){
            System.out.println("存储的数字为空");
            return;
        }

        /**
         * 向左递归
         */
        System.out.printf("arrays[%d] = %d\t", index, arrays[index]);

        if((index * 2 + 1) < arrays.length){
            preSelect(index * 2 + 1);
        }

        /**
         * 向右递归
         */
        if ((index * 2 + 2) < arrays.length){
            preSelect(index * 2 + 2);
        }
    }

    public void midSelect(int index){

        if (this.arrays == null || arrays.length == 0){
            System.out.println("存储的数字为空");
            return;
        }

        /**
         * 向左递归
         */


        if((index * 2 + 1) < arrays.length){
            preSelect(index * 2 + 1);
        }
        System.out.printf("arrays[%d] = %d\t", index, arrays[index]);
        /**
         * 向右递归
         */
        if ((index * 2 + 2) < arrays.length){
            preSelect(index * 2 + 2);
        }
    }

    public void postSelect(int index){

        if (this.arrays == null || arrays.length == 0){
            System.out.println("存储的数字为空");
            return;
        }

        /**
         * 向左递归
         */


        if((index * 2 + 1) < arrays.length){
            preSelect(index * 2 + 1);
        }

        /**
         * 向右递归
         */
        if ((index * 2 + 2) < arrays.length){
            preSelect(index * 2 + 2);
        }

        System.out.printf("arrays[%d] = %d\t", index, arrays[index]);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二叉树代码 的相关文章

  • 粒子滤波器的Matlab实现

    前言 粒子滤波器相较于卡尔曼滤波器或者UKF无迹卡尔曼滤波器而言 可以表达强非线性的变换且无需假设后验分布为高斯分布 在描述多峰分布时具有非常大的优势 粒子滤波器被广泛的应用于机器人系统中 如著名的Gmapping算法便是在粒子滤波器的基础
  • 怎么往阿里云服务器传东西

    https zhidao baidu com question 2075785777388289788 html

随机推荐

  • Unity C# 委托——事件,Action,Func的作用和区别

    参考视频 三分钟彻底搞懂委托 事件 Action Func的作用和区别 哔哩哔哩 bilibili 委托关系图 Delegate 定义两个模板 一个可以传参一个不可以传参 模板 1 public delegate void xxxxx in
  • 复习:最短路径

    一 基本概念 最短路径 在非网图中 最短路径是指两顶点之间经历的边数最少的路径 在网图中 最短路径是指两顶点之间经历的边上权值之和最少的路径 源点 路径上的第一个顶点 终点 路径上最后一个顶点 二 Dijkstra算法 只适用于简单路径 不
  • 最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析

    最小生成树 Prim算法与Kruskal算法 408方向 思路与实现分析 最小生成树 老生常谈了 生活中也总会有各种各样的问题 在这里 我来带你一起分析一下这个算法的思路与实现的方式吧 在考研中呢 最小生成树虽然是只考我们分析 理解就行 但
  • NestedScrollView嵌套RecyclerView只显示一行的问题

    1 添加属性设置 设置布局管理器 LinearLayoutManager linearLayoutManager new LinearLayoutManager context linearLayoutManager setOrientat
  • node写可选参数接口

    个人网站 紫陌 笔记分享网 想寻找共同学习交流 共同成长的伙伴 请点击 前端学习交流群 今天写项目接口看到接口文档要求带四个参数两个参数必选两个可选 当时在想可选参数要怎么做 毕竟自己也没有写过 然后想了一天终于想出一个感觉不是最佳的方案
  • 极简教学

    目录 一 安装wget 二 安装git 三 安装pip 四 下载ChatGLM2 6B源码 五 安装Anaconda 六 安装pytorch 七 下载模型库 八 最后的准备工作 九 运行程序 一 安装wget 1 删除自带的wget yum
  • CAN总线的EMC设计方案

    一 CAN接口EMC设计概述 Controller Area Network简称为CAN 多用于汽车以及工业控制 用于数据的传输控制 在应用的过程中通讯电缆容易耦合外部的干扰对信号传输造成一定的影响 单板内部的干扰也可能通过电缆形成对外辐射
  • kafka多线程实现消费者实战

    前言 KafkaProducer是线程安全的 但是KafkaConsumer不是线程安全的 同一个KafkaConsumer用在了多个线程中 将会报Kafka Consumer is not safe for multi threaded
  • emplace_back和push_back的区别

    相同点 两者都是向容器内添加数据 不同点 当数据为类的对象时 emplace back相对push back可以避免额外的移动和复制操作 以下代码copy from点击打开链接 include
  • LeetCode-917. 仅仅反转字母

    给你一个字符串 s 根据下述规则反转字符串 所有非英文字母保留在原有位置 所有英文字母 小写或大写 位置反转 返回反转后的 s 示例 1 输入 s ab cd 输出 dc ba 来源 力扣 LeetCode 双指针 双指针是一种解决问题的技
  • C++中的虚函数(一)

    虽然很难找到一本不讨论多态性的C 书籍或杂志 但是 大多数这类讨论使多态性和C 虚函数的使用看起来很难 我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C 中的虚函数实现技术 说明一点 写这篇文章只是想和大家交流学习经验因为本人学
  • 互联网项目生产线各环节介绍

    采用敏捷开发模式 每个周期为两周 每次完成5 10个不等的story 然后进入下一个迭代 以此类推 1 需求管理 这个由产品部来负责收集 分析 整理 最终形成一个个可进行开发的story 需求管理工具选用icescrum 2 代码研发 由j
  • flutter image_picker 控件的使用 ---选择系统图片、拍照

    在pubspec yaml中添加依赖 dependencies image picker 0 4 12 1 Dart文件如下 import package flutter material dart import package image
  • CTF_ctfshow_meng新_web1-web24

    打开靶机 发现包含有个config php文件 打开进去没有数据 所以直接开始代码审计吧 有个变量为id 参数必须为1000才能获得flag 但id gt 999直接返回退出了 尝试一下sql注入 整形注入 看一下回显点 回显点为三 版本
  • LTV-MPC

    For compatibility with the adaptive mode the plant model specified in your controller object must be LTI state space OK
  • java中文档注释的标记是_javadoc中文档注释标记的使用

    javadoc中文档注释标记的使用 author 标记 author指定一个类的作者 它的语法如下 author description 其中 description通常是编写这个类的作者名字 标记 author只能用在类的文档中 在执行j
  • PCL 改进体素滤波

    一 改进简介 PCL的VoxelGrid类是通过输入的点云数据创建一个三维体素栅格 用每个体素内用体素中所有点的重心来近似显示体素中的其他点 这样该体素内所有点都用一个重心点来最终表示 该重心点不一定就是原始点云中的点 有失原始点云的细小特
  • 用c语言浮点输出时,如何让小数点后没用的0不显示

    动态控制浮点数小数位数 2020年7月29日 存在问题 C语言把浮点数直接通过sprintf函数保存在字符数组中 末尾的0显得很多余 想办法把末尾的0去掉 解决问题 在打印时 通过格式控制输出 一般情况使用 f即可输出浮点数 我们通过 f
  • linux查看3306是哪个进程占用,linux查看端口占用

    发表于 2019 08 18 21 00 36 by 月小升 一 例子 lsof i 7000 COMMAND PID USER FD TYPE DEVICE SIZE OFF NODE NAME frps 1249 root 3u IPv
  • 二叉树代码

    1 普通二叉树的构建 构建结点以及搜索与删除的方法 public class Node private int no private String name private Node left private Node right priv