【数据结构】树——二叉树

news2025/1/22 18:56:49

1.树的介绍以及树的基本概念和性质

2.二叉树介绍以及二叉树的性质

3.二叉树的构建:穷举创建,递归创建

4.二叉树的基本操作

之前我们介绍了顺序表,链表,以及栈和队列,这几种数据结构都属于线性结构,而我们接下来要讲的树属于非线性结构~

树的数据结构相当于一颗倒挂的树,由n个节点组成,最顶部的节点叫做根节点,最底下的节点称为叶子节点

1.根节点没有前驱节点的信息

2.每个节点都包含1个或者多个节点的后继(比如说根节点A分叉为两个后继节点B和C,也就是说A节点包含B和C节点的信息)

3.树是递归实现的

一棵树包含多个子树,每个子树又有自己的根节点,比如说A节点两边是左树B和右树C,左树B两边也有左树D和右树E……以此类推


接下来来认识一下树的一些常用概念性质(结合下图来认识)

(1)结点的度:一个结点含有子树的个数称为该结点的度;简单来说就是看结点分了多少个叉,A节点分了两个叉,那么A节点的度为6,D结点的度为1,F结点的度为3……

(2)树的度:就是这一整棵树多个子树的度中的最大度,A的度为6,F的度为3……度为6是最大的,所以该树的最大度为6

(3)叶子结点(终端结点):叶子结点也叫终端结点,表示度为0的结点,度为0的结点就是该结点没有分叉,那么B,C,H,I,P,Q,K,L,M,N这些度为0的结点就统称为叶子结点

(4)父结点(双亲结点):父结点也叫做双亲结点,某个结点的前驱就是该结点的父结点,比如说B的前驱是A,那么A就是B结点的父结点,B就是A结点的子结点

(5)孩子结点(子结点):子结单就是某个结点的后继,比如A的后继有B,C,D,E,F,G 这些结点都属于A的子结点,因此!!父结点和子结点是相对而言的~

(6)根结点:一棵树中,没有双亲结点的结点;如上图:A(也就是一颗完整的树的第一个结点)

(7)结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推,因此上图这颗树一共有4层~ A在第一层,BCDEFG在第二层,HIJKLMN在第三层,PQ在第四层

(8)树的高度或深度:树中结点的最大层次; 如上图:树的高度为4


树的以下概念只需了解,在看书时只要知道是什么意思即可:

(1)非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等节点为分支结点

(2)兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点

(3)堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点

(4)结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先

(5)子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙

(6)森林:由m(m>=0)棵互不相交的树组成的集合称为森林


接下来说说二叉树,二叉树才是重点

什么是二叉树?顾名思义,就是两个分叉~简单来说,二叉树的每个结点最多只能分两个叉~

 棵二叉树是结点的一个有限集合,该集合:

1. 或者为空

2. 或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成

意思就是说,一个空结点可以是二叉树,没有结点也可以叫二叉树,然后二叉树分为左右两棵子树,每个结点都可以分为左右两颗子树

1. 二叉树不存在度大于2的结点

2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

(图片来源:比特高博)

然后还有两种特殊的二叉树要介绍一下

(1)满二叉树:简单来说,就是除了叶子结点不分叉以外,其余的所有结点都尽它们所能分成两个叉

 

(2) 完全二叉树:这树的意思就是,你给一整棵树编号,同时从上到下,从左到右去数编号,结点是连在一起的

 看绿框里面的两颗二叉树,第一颗是满二叉树,给它编号后,结点是完美的连起来的(从上到下,从左到右),第二棵树是完全二叉树,从1~6,也是连起来的,至于黄色框的树,本来从5要到6的,结果6没了,意思就是说,从5要到达3的左孩子结点,而不是右孩子结点,要连起来,不能空一个结点,或者说是隔着一个结点~


接下来说说二叉树的性质~(重点)

推导

(1)求第i层的结点,求不出来,但是第i层最大的结点数为 2的i-1次方

(2)求的是一整颗深度为k的二叉树的结点数最大为2的k次方-1个


(3)接下来推到一下 n0 = n2 +1 怎么来的

设结点数为N,n0为叶子结点,n1为度为1的结点,n2为度为2的结点

那么  N = n0 + n1 + n2

一颗二叉树的边为  N-1(有多少个结点,该数就有多少条-1条边)

然后度为1的结点n1提供一条边,度为2的结点n2提供两条边

因此,N-1 = n1 + 2*n2  意思就是有n1条边加上两倍n2条边,就是整棵树的边数

之后联立

1) N = n0 + n1 + n2 

2) N - 1 = n1 + 2 * n2 

可求得  n0 = n2 + 1;


(4)求一棵树的深度,用 log 2为底,幂为(n+1),求的的结果向上取整,意思就是说,一辆车能载10个小朋友,但是25个小朋友就要用3辆车,而不是两辆车


接下来使用枚举来创建一颗二叉树

public class BinaryTree {
    static class TreeNode{
        public char val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode(char val){
            this.val = val;
        }
    }

    //二叉树的根节点
    public TreeNode root;

    //穷举创建二叉树
    public void createTree(){
        TreeNode A = new TreeNode('A');
        TreeNode B = new TreeNode('B');
        TreeNode C = new TreeNode('C');
        TreeNode D = new TreeNode('D');
        TreeNode E = new TreeNode('E');
        TreeNode F = new TreeNode('F');
        TreeNode G = new TreeNode('G');
        TreeNode H = new TreeNode('H');

        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        E.right = H;
        this.root = A;
    }

    //前序遍历
    void preOrder(TreeNode root){
        if(root == null){
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //中序遍历
    void midOrder(TreeNode root){
        if(root == null){
            return;
        }
        midOrder(root.left);
        System.out.print(root.val + " ");
        midOrder(root.right);
    }

    //后序遍历
    void postOrder(TreeNode root){
        if(root == null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

    //获取树中节点个数(左树节点个数加上右树节点个数)
    //子问题思路
    int size1(TreeNode root){
        int count = 0;
        if(root == null){
            return 0;
        }else {
            count++;
        }

        int leftNum = size1(root.left);
        count += leftNum;

        int rightNum = size1(root.right);
        count += rightNum;

        return count;
    }
    int size2(TreeNode root){
        if(root == null) return 0;
        return size2(root.left) + size2(root.right) + 1;
    }

    //遍历思路
    public static int nodeCount;
    void size3(TreeNode root){
        if(root == null){
            return;
        }
        nodeCount++;
        size3(root.left);
        size3(root.right);
    }

    /**
     * 获取叶子节点个数
     */
    //子问题思路
    int getLeafNodeCount1(TreeNode root){
        int count = 0;
        if(root == null){
            return 0;
        }else if(root.left == null && root.right == null){
            count++;
        }
        int leftCount = getLeafNodeCount1(root.left);
        count += leftCount;

        int rightCount = getLeafNodeCount1(root.right);
        count += rightCount;

        return count;
    }

    //遍历思路
    public static int leafCount;
    void getLeafCount(TreeNode root){
        if(root == null){
            return;
        }
        if(root.left == null && root.right == null){
            leafCount++;
        }
        getLeafCount(root.left);
        getLeafCount(root.right);
    }

    /**
     * 获取第k层节点个数
     */
    int KCount(TreeNode root, int k){
        int count = 0;
        if(root == null){
            return 0;
        }
        if(k == 1){
            count++;
        }
        int left = KCount(root.left,k-1);
        count += left;
        int right = KCount(root.right,k-1);
        count += right;
        return count;
    }

    int KCount2(TreeNode root, int k){
        if(root == null) return 0;
        if(k == 1){
            return 1;
        }
        return KCount2(root.left, k-1) + KCount2(root.right,k-1);
    }

    /**
     * 获取树的高度
     */
    int Height(TreeNode root){
        if(root == null) return 0;
        return Math.max(Height(root.left),Height(root.right)) + 1;
    }

    /**
     * 遍历看看树中是否存在value值
     */
    TreeNode find(TreeNode root, char key){
        if(root == null) return null;
        if(root.val == key){
            return root;
        }
        TreeNode ret1 = find(root.left, key);
        if(ret1 != null){
            return ret1;
        }

        TreeNode ret2 = find(root.right, key);
        if(ret2 != null){
            return ret2;
        }

        return null;
    }


    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        return maxDepth(root) >= 0;
    }

    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        int leftHeight = maxDepth(root.left);
        int rightHeight = maxDepth(root.right);

        if(leftHeight >= 0 && rightHeight <= 0 && Math.abs(leftHeight-rightHeight) <= 1){
            return Math.max(leftHeight,rightHeight) + 1;
        }else {
            return -1;
        }
    }

    //层序遍历
    void levelOrder(TreeNode root){
        if(root == null) return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode cur = queue.poll();
            System.out.print(cur.val + " ");
            if(cur.left != null){
                queue.offer(cur.left);
            }
            if(cur.right != null){
                queue.offer(cur.right);
            }
        }
    }
}

遍历分为4种遍历,都是用递归写的

前序遍历:根左右

中序遍历:左根右

后序遍历:左右根

层序遍历:从上到下,从左到右,依次读取

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

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

相关文章

GreenPlum/PostGreSQL表锁处理

GreenPlum/PostGreSQL表锁处理 数据库中遇到表锁的情况&#xff0c;可以通过select * from pg_stat_activity;查看表锁的进程及进程ID&#xff0c;从而取消进程&#xff0c;解锁。 一、模拟表锁 1.1 模拟表数据 创建lock_test表&#xff0c;并随意插入一条数据&#xff0c;…

Oracle自治事务示例演示

自治事务 自治事务&#xff08;Pragma autonomous_transaction&#xff09;&#xff1a;是PL/SQL块中的一个单独事务&#xff0c;与调用或触发自己的事务之间互不干扰&#xff0c;自己commit和rollback不会影响其他事务&#xff0c;也不会被其他事务所影响。 通俗的讲&#xff…

【Android App】在线语音识别功能实现(使用云知声平台与WebSocket 超详细 附源码)

需要源码和相关资源请点赞关注收藏后评论区留下QQ~~~ 一、在线语音识别 云知声的语音识别同样采用WebSocket接口&#xff0c;待识别的音频流支持MP3和PCM两种格式&#xff0c;对于在线语音识别来说&#xff0c;云知声使用JSON串封装报文&#xff0c;待识别的音频以二进制形式发…

webpack打包vue文件+gulp打包sass文件

webpack打包vue文件 1,下载依赖 npm i vue-loader npm i webpack-cli2&#xff0c;编写webpack配置文件 /*** 关于webpack的配置文件*/const path require(path)const { VueLoaderPlugin } require(vue-loader)const glob require(glob) // node自带的读取文件的库 /*** …

会多门编程语言的你,最推荐哪3-5门语言?

如果你还想在编程的路上继续提高&#xff0c;那我建议你至少学习4种编程语言。可用的编程语言有很多&#xff0c;所以选择一种感兴趣的学习就可以了。我这么建议的原因是&#xff0c;要掌握编程&#xff0c;建立信心&#xff0c;提高能力&#xff0c;最简单的办法就是学习多种编…

浅析工作流调度器Azkaban

title: Azkaban系列 第一章 概述 1.1 为什么需要工作流调度器 1、一个完整的数据分析系统通常都是由大量任务单元组成&#xff1a; shell 脚本程序&#xff0c;java 程序&#xff0c;mapreduce 程序、hive 脚本等 2、各任务单元之间存在时间先后及前后依赖关系 3、为了很好地…

TIA西门子博途V18安装教程及注意事项

TIA西门子博途V18安装教程及注意事项 前提条件: TIA Portal V18需要.Net Framework 3.5环境,所以在安装TIA V18之前要先安装它。大家可以在控制面板中的程序和功能中检查是否已经安装,如果没有,可以参考以下步骤自行安装: 操作系统&#x

jsp旅行网系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅行网系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;使用java语…

[附源码]Python计算机毕业设计房屋租赁系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

2022级浙大MEM录取经验过程分享——有需求就要去匹配

我是2022 级 浙大MEM 新录取的考生&#xff0c;去年联考初试取得了213 分的成绩&#xff0c;综合拿到了148分&#xff0c;去年的提面中也拿到了优秀资格&#xff0c;在备考的过程中自己的一些心得体会和经验分享给大家&#xff0c;希望能够有所帮助。我的本科其实比较普通&…

python循环中的continue和break

目录 一.python中的continue 案例1 结果是 注意 案例2 结果是 二.python中的break 案例1 结果是 注意 案例2 结果是 三. python中continue和break的总结 一.python中的continue continue关键字用于:中断本次循环&#xff0c;直接进入下一次循环 continue可以用于:fo…

2.1.2 运算放大器的组成与分类、运算放大器的发展历程

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

1-10嵌入式Linux系统开发与应用|嵌入式Linux|第三章 Linux编程环境|下篇

目录 1.gcc编译器的使用 1.1gcc软件包 1.2一个基本实例 1.3gcc的主要选项 1.3.1指定函数库和包含文件的查找路径 1.3.2出错检查及警告 1.3.3优化选项 优化带来的问题 1.3.4调试选项 2.GNU C扩展简介 3.GNU make管理项目 3.1make简介 使用make管理项目的原因 4.编…

Nginx那些事儿2

负载均衡 当访问的服务具有多个实例时,需要根据某种“均衡”的策略决定请求发往哪个节点,这就是所谓的负载均衡,目的是为了将数据流量分摊到多个服务器执行,减轻每台服务器的压力,从而提高了数据的吞吐量 负载均衡的种类 常见的硬件有NetScaler、F5、Radware和Array等商用的负…

读懂英文文章所需的单词量

简介 备考托福&#xff0c;GRE需要背上万单词&#xff0c;除去考试通关的因素&#xff0c;就想看看是不是真有必要花时间去背那么多单词。 实验使用从初中到GRE不同等级考试要求的单词表&#xff0c;代入Brown文本数据集&#xff0c;评估背会各等级单词后&#xff0c;能看懂多…

基于51单片机的教室智能照明控制系统

硬件方案 本系统以51单片机作为控制模块的核心部件&#xff0c;采用热释红外人体传感器检测人体的存在&#xff0c;采用光敏三极管构成的电路检测环境光的强度&#xff1b;根据教室合理开灯的条件&#xff0c;通过对人体存在信号和环境光信号的识别与判断&#xff0c;完成对教室…

关于浙江22年下半年教师资格证面试报名注册时间

1 哪些考生可以报名 笔试各科成绩合格且在有效期内的并符合各省面试报考条件人员&#xff0c;可参加报名面试&#xff1a; 2 报名分三阶段 12月9日~12日&#xff1a;网上报名 12月5日起开始注册&#xff0c;根据各省报考公告&#xff0c;考生登陆“NTCE-中国教育考试网”(ht…

Delphi记录

文章目录软件安装基础参考书名词释义基本语法常用函数数学运算函数字符处理函数日期时间函数顺序类型函数操作IDE设置去掉Delphi程序启动时的welcome page(欢迎页)设置环境变量的PATH及library的path安装控件如何在Delphi中安装库?安装Add-in-Exprexx安装TMS FlexCel 7.1 D10.…

Java#数据结构----1

目录 一.栈和队列 栈 队列 二.数组和链表 数组 链表 一.栈和队列 栈 栈的特点:后进先出,先进后出 数据进入栈模型的过程称为:压/进栈 数据离开栈模型的过程称为:弹/出栈 队列 队列的特点:先进先出,后进后出 数据从后端进入队列的过程称为: 入队列 数据从前端离开队列的过…

iptables学习

iptables不算是一个真正的防火墙&#xff0c;它是一个配置Linux内核防火墙的命令行工具。将用户的安全设置同步到对应的安全框架–Netfilter。netfilter位于内核空间&#xff0c;iptables位于用户空间。 iptables用于ipv4&#xff0c;ip6tables用于IPv6。 netfilter/ptables 一…