二叉树

简介: 二叉树(Binary tree)是树形结构的一个重要类型。

二叉树


二叉树简介

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分 。



二叉树定义

二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。



二叉树特殊类型

1、满二叉树: 如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
2、完全二叉树: 深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树。
完全二叉树的特点是叶子结点只可能出现在层序最大的两层上,并且某个结点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1。



二叉树性质

性质1: 二叉树的第i层上至多有2^(i-1)(i≥1)个节点 。
性质2: 深度为h的二叉树中至多含有2^h-1个节点。
性质3: 若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有 n0=n2+1
性质4: 具有n个节点的完全二叉树深为log2x+1(其中x表示不大于n的最大整数)。



java代码实现

// 二叉树
public class BinaryTreeDemo {
    public static void main(String[] args) {
        HeroNode node1 = new HeroNode(1, "宋江");
        HeroNode node2 = new HeroNode(2, "吴用");
        HeroNode node3 = new HeroNode(3, "卢俊义");
        HeroNode node4 = new HeroNode(4, "林冲");
        HeroNode node5 = new HeroNode(5, "关胜");


        BinaryTree root = new BinaryTree(node1);
        node1.setLeft(node2);
        node1.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);

        System.out.println("前序遍历结果为:");
        root.preOrder();
        System.out.println("中序遍历结果为:");
        root.infixOrder();
        System.out.println("后序遍历结果为:");
        root.postOrder();

        System.out.println("前序查找的结果为:");
        HeroNode preNode = root.preOrderSreach(5);
        if (preNode != null) {
            System.out.println("前序查找,查到的信息为:id=" + preNode.getId() + ",name=" + preNode.getName());
        } else {
            System.out.println("前序遍历没有查询到结果。");
        }

        System.out.println("中序查找的结果为:");
        HeroNode infixNode = root.infixOrderSreach(5);
        if (infixNode != null) {
            System.out.println("中序查找,查到的信息为:id=" + infixNode.getId() + ",name=" + infixNode.getName());
        } else {
            System.out.println("中序遍历没有查询到结果。");
        }

        System.out.println("后序查找的结果为:");
        HeroNode postNode = root.postOrderSreach(5);
        if (postNode != null) {
            System.out.println("后序查找,查到的信息为:id=" + postNode.getId() + ",name=" + postNode.getName());
        } else {
            System.out.println("后序遍历没有查询到结果。");
        }

        System.out.println("删除前的二叉树,前序遍历顺序:");
        root.preOrder();
        if (root.delNode(3)) {
            System.out.println("id=3删除成功");
        } else {
            System.out.println("删除失败");
        }

        System.out.println("删除后的二叉树,前序遍历顺序:");

        root.preOrder();


    }
}


//创建二叉树
class BinaryTree {
    private HeroNode root;  //二叉树的根节点

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

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

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

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

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

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

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

    //删除结点
    //先判断当前的root是不是待删除结点 如果是就删除整颗二叉树,如果不是再调用结点的删除方法
    public Boolean delNode(int no) {
        if (root == null) {
            return false;
        } else {
            if (root.getId() == no) {
                root = null;
                return true;
            } else {
                return root.delNode(no);
            }
        }
    }

}


//创建节点的类
class HeroNode {
    private int id;
    private String name;
    private HeroNode left;  // 默认为空
    private HeroNode right;  // 默认为空

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    /**
     * 前序遍历思路
     * 1.输出当前节点
     * 2.判断段当前节点的左子节点是否为空,递归前序遍历
     * 3.判断当前节点的右子节点是否为空,递归前序遍历
     */
    public void preOrder() {
        System.out.println(this);

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

    /**
     * 中续遍历思路
     * 1.判断段当前节点的左子节点是否为空,递归中序遍历
     * 2.输出当前节点
     * 3.判断当前节点的右子节点是否为空,递归中续遍历
     */
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    /**
     * 后续遍历思路
     * 1.判断段当前节点的左子节点是否为空,递归后序遍历
     * 2.判断当前节点的右子节点是否为空,递归后续遍历
     * 3.输出当前节点
     */
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }
        if (this.right != null) {
            this.right.postOrder();
        }
        System.out.println(this);
    }

    /**
     * 前序遍历查找的思路
     * 1.判断当前节点是否为待查找节点,如果是直接返回,
     * 2.判断当前节点的左子节点是否为空,不为空则向左递归前序查找,找到则返回,找不到则返回null
     * 3.判断当前节点的右子节点是否为空,不为空则向右递归前序查找,找到则返回,找不到则返回null
     *
     * @param no 带查找的节点id
     * @return 返回该节点的信息
     */
    public HeroNode preOrderSreach(int no) {
//        System.out.println("前序遍历的次数~~~");

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

        HeroNode heroNode = null;
        //判断当前节点的左子节点是否为空,不为空则向左递归前序查找,找到则返回,找不到则返回null
        if (this.left != null) {
            heroNode = this.left.preOrderSreach(no);
        }
        if (heroNode != null) {
            return heroNode;
        }
        //判断当前节点的右子节点是否为空,不为空则向右递归前序查找,找到则返回,找不到则返回null
        if (this.right != null) {
            heroNode = this.right.preOrderSreach(no);
        }
        return heroNode;
    }


    /**
     * 中序遍历查找的思路
     * 1.判断当前节点的左子节点是否为空,不为空则向左递归中序查找,找到则返回,找不到则返回null,
     * 2.判断当前节点是否为待查找节点,如果是直接返回
     * 3.判断当前节点的右子节点是否为空,不为空则向右递归中序查找,找到则返回,找不到则返回null
     *
     * @param no 带查找的节点id
     * @return 返回该节点的信息
     */
    public HeroNode infixOrderSreach(int no) {
        HeroNode heroNode = null;
        //判断当前节点的左子节点是否为空,不为空则向左递归中序查找,找到则返回,找不到则返回null
        if (this.left != null) {
            heroNode = this.left.infixOrderSreach(no);
        }
        if (heroNode != null) {
            return heroNode;
        }
//        System.out.println("中序遍历的次数~~~");

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

        //判断当前节点的右子节点是否为空,不为空则向右递归中序查找,找到则返回,找不到则返回null
        if (this.right != null) {
            heroNode = this.right.infixOrderSreach(no);
        }
        return heroNode;
    }


    /**
     * 后序遍历查找的思路
     * 1.判断当前节点的左子节点是否为空,不为空则向左递归后序查找,找到则返回,找不到则返回null,
     * 2.判断当前节点的右子节点是否为空,不为空则向右递归后序查找,找到则返回,找不到则返回null
     * 3.判断当前节点是否为待查找节点,如果是直接返回
     *
     * @param no 带查找的节点id
     * @return 返回该节点的信息
     */
    public HeroNode postOrderSreach(int no) {
        HeroNode heroNode = null;
        //判断当前节点的左子节点是否为空,不为空则向左递归后序查找,找到则返回,找不到则返回null
        if (this.left != null) {
            heroNode = this.left.postOrderSreach(no);
        }
        if (heroNode != null) {
            return heroNode;
        }
        //判断当前节点的右子节点是否为空,不为空则向右递归后序查找,找到则返回,找不到则返回null
        if (this.right != null) {
            heroNode = this.right.postOrderSreach(no);
        }
        if (heroNode != null) {
            return heroNode;
        }
//        System.out.println("后序遍历的次数~~~~");

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

        return heroNode;
    }


    /**
     * 删除结点的思路
     * 1.因为二叉树是单向是的,所以删除的时候只能删除当前结点的下一个结点。
     * 2.如果当前的左子节点不为空,判断当前的左子结点是否为待删除结点,如果是领this.left=null,让后返回true。
     * 3.如果当前的右子节点不为空,判断当前的右子结点是否为待删除结点,如果是就领this.right=null,让后返回true。
     * 4.如果 2 , 3 都没有找到待删除结点就向左递归,
     * 5.如果向左递归没有找到就向右递归
     *
     * @param no 待删除结点的id
     * @return 返回是否删除成功
     */
    public Boolean delNode(int no) {
        if (this.left != null && this.left.id == no) {
            this.left = null;
            return true;
        }
        if (this.right != null && this.right.id == no) {
            this.right = null;
            return true;
        }
        if (this.left != null) {
            if (this.left.delNode(no)) {
                return true;
            }
        }
        if (this.right != null) {
            if (this.right.delNode(no)) {
                return true;
            }
        }
        return false;
    }

}
目录
相关文章
|
算法 数据可视化 新能源
数字化营销助力哪吒汽车突破重围 进店率单月提升4倍
数字化营销助力哪吒汽车突破重围 进店率单月提升4倍
380 0
|
开发工具 C++ git
《人生苦短,我用python·三》pybind11简单使用
《人生苦短,我用python·三》pybind11简单使用
1103 0
|
6天前
|
存储 人工智能 自然语言处理
从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
本文详解如何从零搭建RAG(检索增强生成)应用,跳过LangChain等框架,深入掌握文本解析、分块、向量检索、对话记忆、指代消解等核心技术,提升系统可控性与优化能力。
80 0
从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
|
2天前
|
机器学习/深度学习 数据采集 算法
基于VMD-CPA-KELM-IOWAl-CSA-LSSVM碳排放的混合预测模型研究(Matlab代码实现)
基于VMD-CPA-KELM-IOWAl-CSA-LSSVM碳排放的混合预测模型研究(Matlab代码实现)
|
存储 设计模式 前端开发
MVC架构和DDD架构的区别?
最近在学习一个开源社区项目,第一次听说了DDD项目架构,于是通过搜索之后来分享给大家
|
运维 监控 Devops
云效DevOps:不仅仅是工具,更是思维方式的转变
【6月更文挑战第11天】云效DevOps是软件行业的 game changer,超越技术工具层面,推动协作、自动化和持续改进的思维转型。它连接开发、测试、运维,强化团队协作,通过自动化提升效率和准确性,减少人为错误。示例展示了自动化构建过程,强调每次迭代都是改进机会,促进项目持续优化和竞争力提升。
250 3
|
存储 Kubernetes 固态存储
k8s调度之初探nodeSelector和nodeAffinity
k8s调度之初探nodeSelector和nodeAffinity
402 0
|
Java 程序员
JavaIO编程(键盘输入,缓冲输入流、Scanner工具、序列化与反序列化)附带相关面试题
1.System类对io的支持,2.BufferReader缓冲输入流,3.Scanner输入流工具,4.对象序列化
141 0
|
API
适配器(Adapter)模式
适配器(Adapter)模式
203 0
|
存储 Java 芯片
首款RISC-V笔记本电脑疑曝光,或配Windows系统,年底能来吗
首款RISC-V笔记本电脑疑曝光,或配Windows系统,年底能来吗
281 0