当前位置: 首页 > news >正文

二叉树解析

二叉树的定义

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

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

在这里插入图片描述

从图可知:

  • 二叉树不存在度大于2的结点。
  • 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。

二叉树的形态

五种基本形态

在这里插入图片描述

三种特殊形态

  1. 斜二叉树:所有结点仅含左子或右子,呈斜线状,节点数n则高度为n 。
  2. 满二叉树:分支结点均有左右子树,叶子结点在同一层,深度h时节点数为(2h - 1) 。
  3. 完全二叉树:按层序编号与同深度满二叉树对应位置一致,是满二叉树少最右若干叶子的形态 。

在这里插入图片描述
注意:满二叉树是一种特殊的完全二叉树。

二叉树的性质

1.若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2i-1(i>0)个结点。

2.若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是2k-1(k>=0)。

3.对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1。

证明:总结点个数n = n0 + n1 + n2;总结点中除根结点外,其余各结点都有一个分支进入,设m为分支总数,则有n = m + 1;又因为这些分支都是由度为1或2的结点射出的,所以有m = n1 + 2n2;于是有n = n1 + 2n2 + 1,最后将关于n的两个关系式化简得证。

4.具有n个结点的完全二叉树的深度k为log2(n+1)为上取整。

5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:

  • 若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点。
  • 若2i+1<n,左孩子序号:2i+1,否则无左孩子。
  • 若2i+2<n,右孩子序号:2i+2,否则无右孩子。

二叉树的存储

二叉树的存储结构分为:顺序存储和类似于链表的链式存储。

1.顺序存储:

使用一组地址连续的存储单元存储,例如数组。为了在存储结构中能得到父子结点之间的映射关系,二叉树中的结点必须按层次遍历的顺序存放。具体是:

  • 对于完全二叉树,只需要自根结点起从上往下、从左往右依次存储。
  • 对于非完全二叉树,首先将它变换为完全二叉树,空缺位置用某个特殊字符代替(比如#),然后仍按完全二叉树的存储方式存储。

顺序存储非常适合存储接近完全二叉树类型的二叉树,对于一般二叉树有很大的空间浪费,所以对于一般二叉树,一般用下面这种链式存储。

2.链式存储:

对每个结点,除数据域外再多增加左右两个指针域,分别指向该结点的左孩子和右孩子结点,再用一个头指针指向根结点。对应的存储结构:

在这里插入图片描述

二叉树的基本操作

二叉树的遍历

遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。

1.前中后序遍历

二叉树由三个基本单元组成:根结点,左子树,右子树,因此存在6种遍历顺序,若规定先左后右,则只有一下三种:

  • NLR:前序遍历(Preorder Traversal)—访问根结点–>根的左子树–>根的右子树。
  • LNR:中序遍历(Inorder Traversal)—根的左子树–>根节点–>根的右子树。
  • LRN:后序遍历(Postorder Traversal)—根的左子树–>根的右子树–>根节点。
class Node {int val;Node left;Node right;Node(int val) {this.val = val;this.left = null;this.right = null;}
}public class BinaryTreeTraversal {// 前序遍历:根 -> 左 -> 右void preOrder(Node root) {if (root == null) {return;}// 访问根节点,这里简单打印节点值示例System.out.print(root.val + " "); preOrder(root.left);preOrder(root.right);}// 中序遍历:左 -> 根 -> 右void inOrder(Node root) {if (root == null) {return;}inOrder(root.left);// 访问根节点,这里简单打印节点值示例System.out.print(root.val + " "); inOrder(root.right);}// 后序遍历:左 -> 右 -> 根void postOrder(Node root) {if (root == null) {return;}postOrder(root.left);postOrder(root.right);// 访问根节点,这里简单打印节点值示例System.out.print(root.val + " "); }
}

仔细观察先序、中序、后序的结点访问顺序可以发现:

img

2.层序遍历:

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述

二叉树的基本操作

class Node {int val;Node left;Node right;Node(int val) {this.val = val;this.left = null;this.right = null;}
}public class BinaryTreeOperations {// 获取树中节点的个数int size(Node root) {if (root == null) {return 0;}// 根节点 + 左子树节点数 + 右子树节点数return 1 + size(root.left) + size(root.right); }// 获取叶子节点的个数int getLeafNodeCount(Node root) {if (root == null) {return 0;}// 左右子节点都为空,是叶子节点if (root.left == null && root.right == null) { return 1;}// 左子树叶子数 + 右子树叶子数return getLeafNodeCount(root.left) + getLeafNodeCount(root.right); }// 获取第 k 层节点的个数(k 从 1 开始)int getKLevelNodeCount(Node root, int k) {if (root == null || k < 1) {return 0;}if (k == 1) {// 第 1 层只有根节点return 1; }// 递归求左、右子树第 k - 1 层节点数之和return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1); }// 获取二叉树的高度int getHeight(Node root) {if (root == null) {return 0;}// 树的高度 = 1 + 左右子树较高的高度int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);return 1 + Math.max(leftHeight, rightHeight); }// 检测值为 value 的元素是否存在,存在返回对应节点,不存在返回 nullNode find(Node root, int val) {if (root == null) {return null;}if (root.val == val) {return root;}// 先在左子树找Node leftFind = find(root.left, val); if (leftFind != null) {return leftFind;}// 左子树没找到,在右子树找return find(root.right, val); }// 层序遍历(借助队列实现)void levelOrder(Node root) {if (root == null) {return;}java.util.LinkedList<Node> queue = new java.util.LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {Node node = queue.poll();// 访问节点,这里简单打印节点值示例System.out.print(node.val + " "); if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}}// 判断一棵树是不是完全二叉树(借助队列,按层遍历特性判断)boolean isCompleteTree(Node root) {if (root == null) {return true;}java.util.LinkedList<Node> queue = new java.util.LinkedList<>();queue.offer(root);boolean isLeafStage = false;while (!queue.isEmpty()) {Node node = queue.poll();if (isLeafStage) {// 进入叶子阶段后,后续节点必须是叶子(无左右子节点)if (node.left != null || node.right != null) { return false;}} else {if (node.left != null && node.right != null) {queue.offer(node.left);queue.offer(node.right);} else if (node.left != null && node.right == null) {queue.offer(node.left);isLeafStage = true;} else if (node.left == null && node.right != null) {// 左空右不空,不是完全二叉树return false; } else {isLeafStage = true;}}}return true;}
}
http://www.dtcms.com/a/294906.html

相关文章:

  • 51c大模型~合集158
  • RockyLinux 9.6 解决删除home后无法开机问题
  • 视觉BPE统一多模态理解-北大
  • Python+大模型 day03
  • 面试实战,问题四,介绍一下dubbo框架,如何回答
  • 河南萌新联赛2025第二场-河南农业大学
  • 解决uniapp 使用uview生成小程序包太大无法上传的问题
  • 亚马逊广告优化技巧:如何减少预算浪费
  • Tang Prime 20K板I2S输入输出例程
  • lumerical——光纤布拉格光栅(Fiber Bragg gratings)
  • AI驱动攻防升级,API安全走到关键档口
  • MyBatis整合SpringBoot终极指南
  • 设备维修记录可追溯:管理系统选型指南
  • ESP32-S3 小电视学习笔记2:Arduino开发环境搭建(垃圾)
  • PyTorch深度学习入门记录2
  • sql注入171到185
  • 使用Qemu模拟Arm处理器,运行Linux系统
  • 做了个震动APP
  • 学生信息管理系统 - HTML实现增删改查
  • odoo欧度小程序——添加用户
  • 面试150 合并K个升序链表
  • 智能制造基础-全面质量管理(TQM)
  • 嵌入式学习-土堆目标检测(4)-day28
  • iview表单验证一直提示为空的几个原因?
  • 1.C语言和其关键字的一个简单介绍
  • Spring事务注解详解:确保你的应用数据的一致性
  • 解决BAPI_ACC_DOCUMENT_POST 功能范围输入不生效问题
  • OpenAI o系列模型Responses接口开发Python代码示例
  • 【机器学习深度学习】生成式模型的评估与验证
  • linux驱动开发笔记--GPIO驱动开发