二叉树

简介: 二叉树(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倍
421 0
|
开发工具 C++ git
《人生苦短,我用python·三》pybind11简单使用
《人生苦短,我用python·三》pybind11简单使用
1321 0
|
XML 前端开发 Java
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
760 0
|
2月前
|
存储 人工智能 自然语言处理
从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
本文详解如何从零搭建RAG(检索增强生成)应用,跳过LangChain等框架,深入掌握文本解析、分块、向量检索、对话记忆、指代消解等核心技术,提升系统可控性与优化能力。
321 0
从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
|
3月前
|
前端开发 测试技术 API
国产 API 管理工具大比拼:Apifox 能否挑战 Postman?
在软件开发中,API 测试与管理工具至关重要。Postman 虽广受欢迎,但在国内常面临下载慢、注册难、功能收费等问题。Apifox 作为国产优秀替代工具,凭借简洁的界面、多功能集成、本地化服务等优势,逐渐成为开发团队的新选择。它支持接口设计、文档生成、Mock 服务、自动化测试等功能,提升团队协作效率,降低使用门槛,助力国内开发者实现高效开发与持续集成。
|
7月前
|
移动开发 小程序 前端开发
《Taro框架:微信生态下的开发利器》
Taro框架作为高效开发工具,在微信小程序生态中脱颖而出。它支持“一次编写,多端运行”,极大提升代码复用率和开发效率,尤其适合电商、生活服务和社交类小程序开发。基于React生态,Taro可复用丰富组件,降低学习成本,并通过灵活插件扩展功能。其组件化开发模式促进团队协作,优化配置满足个性化需求,为开发者在微信生态中实现创新应用提供了强大支持。
195 17
|
监控 关系型数据库 MySQL
Nightingale——滴滴夜莺部署【一】
Nightingale——滴滴夜莺部署【一】
429 0
Nightingale——滴滴夜莺部署【一】
|
C# 机器学习/深度学习 搜索推荐
WPF与机器学习的完美邂逅:手把手教你打造一个具有智能推荐功能的现代桌面应用——从理论到实践的全方位指南,让你的应用瞬间变得高大上且智能无比
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)应用中集成机器学习功能,以开发具备智能化特性的桌面应用。通过使用Microsoft的ML.NET框架,本文演示了从安装NuGet包、准备数据集、训练推荐系统模型到最终将模型集成到WPF应用中的全过程。具体示例代码展示了如何基于用户行为数据训练模型,并实现实时推荐功能。这为WPF开发者提供了宝贵的实践指导。
326 0
|
存储 设计模式 前端开发
MVC架构和DDD架构的区别?
最近在学习一个开源社区项目,第一次听说了DDD项目架构,于是通过搜索之后来分享给大家
|
机器学习/深度学习 人工智能 搜索推荐
人工智能在在线教育中的个性化学习推荐
人工智能在在线教育中的个性化学习推荐
357 1

热门文章

最新文章