【数据结构与算法】详解二叉树以及模拟实现二叉树

news/2024/11/29 9:37:25/

文章目录

  • 前言:
  • 1.二叉树的定义
  • 2.二叉树的相关术语
  • 3.二叉树的性质
  • 4.特殊的二叉树
  • 5.二叉树的遍历
    • 前序遍历
    • 中序遍历
    • 后序遍历
    • 层序遍历
  • 6.获取树中节点的个数
    • 方法1:遍历思想
    • 方法2:子问题的思想
  • 7.获取叶子节点的个数
    • 方法1:遍历思想
    • 方法2:子问题的思想
  • 8.获取第K层节点的个数
  • 9.获取二叉树的高度
  • 10.检测值为value的元素是否存在
  • 11.判断一棵树是不是完全二叉树

前言:

二叉树在学习数据结构中是一种很重要的类型,也是学习数据结构中比较困难的一种结构,但是在平时用的也是非常多,因此二叉树尤为重要.
本篇文章中会涉及到大量的递归代码,如果一些地方不太理解,可以尝试画图梳理代码执行流程
关于文章中的二叉树源码→点击即可跳转 需要的可以去看一看

1.二叉树的定义

在这里插入图片描述

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

2.二叉树的相关术语

①节点:包含一个数据元素及若干指向子树分支的信息 。
②节点的度:一个节点拥有子树的数目称为节点的度 。
③叶子节点:也称为终端节点,没有子树的节点或者度为零的节点。
④分支节点:也称为非终端节点,度不为零的节点称为非终端节点 。
⑤树的度:树中所有节点的度的最大值。
⑥节点的层次:从根节点开始,假设根节点为第1层,根节点的子节点为第2层,依此类推,如果某一个节点位于第L层,则其子节点位于第L+1层。
⑦树的深度:也称为树的高度,树中所有节点的层次最大值称为树的深度。
⑧有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树。
⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树。
⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成

3.二叉树的性质

性质1:二叉树的第i层上至多有2i-1(i≥1)个节点 。
性质2:深度为h的二叉树中至多含有2h-1个节点。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1。
性质4:具有n个节点的满二叉树深为log2n+1。
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:
当i=1时,该节点为根,它无双亲节点 。
当i>1时,该节点的双亲节点的编号为i/2 。
若2i≤n,则有编号为2i的左节点,否则没有左节点 。
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点 。

4.特殊的二叉树

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

5.二叉树的遍历

二叉树的遍历主要有前序遍历,中序遍历,后序遍历以及层序遍历,前面三种遍历主要是采用递归的方式进行遍历的,如果看不懂,建议画图梳理一下代码执行流程

前序遍历

        public void preOrder(TreeNode root) {if(root == null){return;}System.out.print(root.val+" ");preOrder(root.left);preOrder(root.right);}

中序遍历

        public void inOrder(TreeNode root) {if(root == null){return;}inOrder(root.left);System.out.print(root.val+" ");inOrder(root.right);}

后序遍历

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

层序遍历

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

6.获取树中节点的个数

方法1:遍历思想

    public static int nodeSize = 0;// 记录二叉树的结点个数public void size(TreeNode root) {if(root == null){return;}nodeSize++;size(root.left);size(root.right);}

方法2:子问题的思想

    public int size2(TreeNode root) {if(root == null){return 0;}// 难点 -> 画图 在叶子结点时 会返回1 根是最后加上的return size2(root.left)+size2(root.right)+1;}

7.获取叶子节点的个数

叶子结点的左子树和右子树都为null,因此只要看哪些结点符合条件的就可以了

方法1:遍历思想

    public static int leafSize = 0;public void getLeafNodeCount1(TreeNode root) {if(root == null){return;}if(root.left == null && root.right == null){leafSize++;}getLeafNodeCount1(root.left);getLeafNodeCount1(root.right);}

方法2:子问题的思想

    public int getLeafNodeCount2(TreeNode root) {if(root == null){return 0;}if(root.left == null && root.right == null){return 1;}return getLeafNodeCount2(root.left)+getLeafNodeCount2(root.right);}

8.获取第K层节点的个数

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

9.获取二叉树的高度

    public int getHeight(TreeNode root) {if(root == null){return 0;}int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);return leftHeight > rightHeight ? leftHeight+1 : rightHeight+1;}

10.检测值为value的元素是否存在

这里实现的时候返回值设置的是TreeNode,如果不喜欢可以换成boolean

    public TreeNode find(TreeNode root, char val) {if(root == null) {return null;}if(root.val == val){return root;}TreeNode treeNode1 = find(root.left,val);if(treeNode1 != null){return treeNode1;}TreeNode treeNode2 = find(root.right,val);if(treeNode2 != null){return treeNode2;}return null;}

11.判断一棵树是不是完全二叉树

判断是不是完全二叉树,这里使用的是队列做的.也涉及到分层遍历的思想,将每层的结点以及最后一层结点的孩子结点存下来,然后对第一次出现null时后的数据开始进行判断.如果是完全二叉树,那么最后一次遍历的数据都是null,如果不是完全二叉树,那么就是结点和null并存的情况,而且一定是在结点前有个null

    public boolean isCompleteTree(TreeNode root) {if (root == null) {return true;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){TreeNode cur = queue.poll();if (cur != null){queue.offer(cur.left);queue.offer(cur.right);}else {break;}}while (!queue.isEmpty()) {TreeNode ret = queue.poll();if (ret != null){return false;}}return true;}

在这里插入图片描述


http://www.ppmy.cn/news/18565.html

相关文章

处理查询结果集

package com.bjpowernode.jdbc;import java.sql.*; /**处理查询结果集提醒&#xff1a;JDBC中所有的下标都是从1开始的。*/ public class 处理查询结果集 {public static void main(String[] args){Connection conn null;Statement stmt null;ResultSet rs null;try{//1、注…

自增id用完怎么办?

MySQL 里有很多自增的 id,每个自增 id 都是定义了初始值,然后不停地往上加步长。虽然自然数是没有上限的,但是在计算机里,只要定义了表示这个数的字节长度,那它就有上限。比如,无符号整型 (unsigned int) 是 4 个字节,上限就是 232-1。 既然自增 id 有上限,就有可能被…

函数——“C”

各位CSDN的uu们新年快乐呀&#xff0c;祝大家越来越开心&#xff0c;越来越优秀。那行&#xff0c;让我们进入今天的正题&#xff0c;来了解了解函数&#xff0c;函数是什么&#xff0c;C语言中函数是如何分类的&#xff0c;函数参数&#xff0c;函数调用等一系列小知识点&…

第十三届蓝桥杯省赛JavaA组 D 题、Java C 组 G 题、Python C 组 G题——GCD(AC)

1.GCD 1.题目描述 给定两个不同的正整数 a,ba,ba,b 求一个正整数 kkk 使得 gcd(ak,bk)gcd(ak,bk)gcd(ak,bk) 尽可能 大,其中 gcd(a,b)gcd(a,b)gcd(a,b) 表示 aaa 和 bbb 的最大公约数&#xff0c;如果存在多个 kkk, 请输出所有满 足条件的 kkk 中最小的那个。 2.输入格式 输…

在甲骨文云容器实例(Container Instances)上部署firefox

甲骨文云推出了容器实例&#xff0c;这是一项无服务器计算服务&#xff0c;可以即时运行容器&#xff0c;而无需管理任何服务器。 今天我们尝试一下通过容器实例部署firefox。 Step1. 创建容器实例 在甲骨文容器实例页面&#xff0c;单击"创建容器实例"&#xff0c…

FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(三)

第七章 实战项目提升&#xff0c;完善简历 19.OV7725摄像头实时采集送HDMI显示&#xff08;三&#xff09; 在详细介绍过OV7725 CMOS Sensor的相关背景知识和如何初始化其内部寄存器达到输出预期视频流的目的后&#xff0c;就到了该例程的核心内容即把OV7725输出的视频流预先缓…

FFmpeg 将多张图片编码成视频

前言 本篇文章的需求是将相机获取到的图片进行编码&#xff0c;编码成一个视频&#xff0c;耗费了大约一个星期的时间在解决各种问题。这里阐述一下这篇文章所要解决的几个问题&#xff1a; 1、如何将多张图片编码成视频。 2、如何进行定时录制视频。 3、同时开启多线程进行视…

【网络安全】WiFi密码爆破教程

WiFi密码爆破教程前言一、什么是暴力破解&#xff1f;二、准备破解工具1.VMware Pro 16 虚拟机安装2. VMware安装Kali Linux3. kali监听无限网卡三、WiFi密码暴力破解1. 虚拟机连接USB网卡2. 扫描附近WiFi3. 查看目标WiFi连接设备4. 抓包5. 破解前言 暴力破解攻击是指攻击者通…