跳到主要内容
数据结构复习:二叉树的概念、性质与遍历实现 | 极客日志
Java java 算法
数据结构复习:二叉树的概念、性质与遍历实现 树型结构与二叉树的基础知识。涵盖树形结构特点、基本术语及表现形式;详细讲解了二叉树的概念、满二叉树与完全二叉树的定义;阐述了二叉树的五条核心性质。重点实现了二叉树的三种递归遍历方式(前序、中序、后序)及其特点对比,并提供了获取节点数、叶子节点数、第 k 层节点数、树高、元素查找及层序遍历等常用操作的 Java 代码实现。
山野诗人 发布于 2026/3/23 更新于 2026/7/25 4.2K 浏览一、树型结构
树型结构是一种非线性的数据结构,它是由节点和边组成的,有一个特定的节点被称为根节点,其余节点通过边连接形成的层次关系,将它称为树是因为看起来像一棵倒挂的树:
树形结构:
1. 树形结构的特点
层次分明:数据和结构之间存在明确的层次关系,便于表示和理解具有层次特征的信息
递归性:许多树形结构的操作都是通过递归的方式实现的
有序性:节点的子节点之间可能存在特定的顺序
有一个特殊的节点。称为根节点,根节点没有前驱节点
在我们的树形结构中,子树之间是不能有交集的否则就不是树形结构啦
2. 非树形结构
在树型结构的概念中:
子树是不相交的;除了根节点外,每个节点有且只有一个父节点;一棵 N 个节点的树有 N-1 条边;
但是在下图可以发现 G 这个节点是有两个父节点的,并且只有 10 个节点却有 11 条边,所以这不是我们意义上的树形结构
3. 树型结构的基本特性
**结点的度:**一个结点含有子树的个数成为该结点的度;例如上图:A 结点的度为 3
**树的度:**一棵树中,所有结点度的最大值称为树的度;例如上图:树的度为 6
叶子结点或终端结点 :度为 0 的结点称为叶子结点;例如上图:K、F、G、H、I、J 就是叶子结点
**双亲结点或父结点:**若一个结点含有子结点,则这个结点称为其子结点的父结点;例如上图:E 是 K 的父结点
**孩子结点或子结点:**一个结点含有的子树的根节点称为该结点的子结点:例如上图:B 是 A 的子结点
**根结点:**一棵树中,没有双亲结点的结点:例如上图:A 结点就是根结点
**结点的层次:**从根结点开始定义,根为第一层。根的子结点为第二层,以此类推
**树的高度或者深度:**树中结点的最大层次;例如上图:树的高度为 4
**非终端结点或分支结点:**度不为 0 的结点;例如上图:B、C、D、E 结点为分支结点
**兄弟结点:**具有相同父结点的结点互称为兄弟结点;例如上图:B、C、D 是兄弟结点
**堂兄弟结点:**双亲在同一层的结点互为堂兄弟;例如上图:F、G 互为堂兄弟结点
**结点的祖先:**从根到该结点所经分支上的所有结点;例如上图:A 是所有结点的祖先
**子孙:**以某个结点为根的子树中任一结点都称为该结点的子孙;例如上图:所有结点都是 A 的子孙
**森林:**由 m(m>=0)课互不相交的树组成的集合称为森林
4. 树的表现形式 树型结构相对线性表来说比较复杂,有很多种表示方式:双亲表示法、孩子表示法、孩子双亲表示法、孩子兄弟表示法等等;其中最常用的就是孩子兄弟表示法:
class Node {
int value;
Node firstChild;
Node nextBrother;
}
二、二叉树 上面我们了解了什么是树型结构,接下来看看什么是二叉树
2.1 二叉树的概念 二叉树是一种树型结构,但是二叉树中的每个结点最多有两个子结点,分别称为左结点和右结点
二叉树不存在度大于 2 的结点
二叉树有左子树和右子树之分,所以次序是不能颠倒的,因此二叉树是一颗有序树
2.2 特殊的二叉树 上图演示的其实是一个最普通的二叉树,在二叉树的概念中有两种二叉树比较特殊,我们一起来看看吧
(1) 满二叉树 当一棵二叉树,如果每一层的结点都达到最大值,那么这棵树就是满二叉树:
从上图可以发现:该树的层数为 3,结点总数为 2^3-1=7,那么也就是说,如果一棵二叉树的层数为 K,结点总数为 2^K-1,那么它就是一棵满二叉树。
(2) 完全二叉树 假设一个二叉树的深度为 n,那么除了第 n 层,其他每一层的节点数都达到了最大个数,最后一层的结点按照从左到右的顺序,依次进行排列:
满二叉树是一个特殊的完全二叉树,并且完全二叉树是效率很高的数据结构~
2.3 二叉树的性质 1. 若规定根结点的层数为 1,那么一棵非空二叉树的第 i 层最多有 2^(i-1) 个结点:例如上图的满二叉树,第 4 层有 2^(4-1)=8 个结点;
2. 若规定只有根结点的二叉树深度为 1,则深度为 K 的二叉树最大结点数是 2^K-1:例如上图的满二叉树,深度为 4,那么该树(刚好是满二叉树)的最大结点数就是 2^4-1=15 个结点;
3. 对任何一棵二叉树,如果其叶子结点个数为 n0,度为 2 的非叶子结点个数为 n0=n2+1:
从上图可以看到:叶子结点的个数为 5 个,度为 2 的非叶子结点的个数为 4 个(n0=n2+1);
4. 具有 n 个结点的完全二叉树的深度 K 为 log2(n+1) 上取整 +1:
5. 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的顺序从 0 开始编号,那么对于序号为 i 的结点有:
若 i>0,双亲序号:(i-1)/2;i=0,i 为根结点编号,无双亲结点;
若 2i+1<n,左孩子序号:2i+1,否则无左孩子;
若 2i+2<n,右孩子序号:2i+2,否则无右孩子;
2.4 二叉树的创建 public class Binary_Tree {
static class TreeNode {
public TreeNode left;
public TreeNode right;
char value;
public TreeNode (char val) {
this .value = val;
}
}
public static TreeNode 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' );
A.left=B; A.right=C;
B.left=D; B.right=E;
C.left=F; C.right=G;
return A;
}
public static void main (String[] args) {
TreeNode tree=createTree();
}
}
那么这样一棵二叉树就创建好了,接下来我们来看看该如何遍历这棵二叉树吧
2.5 二叉树的遍历 所谓遍历 (Traversal) 就是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。二叉树的遍历主要有三种方式:前序遍历、中序遍历、后序遍历,我们来看看这三种遍历方式是如何遍历的
(1) 前序遍历 前序遍历的顺序是:根节点--->左子树---->右子树的顺序进行遍历的,对于每棵子树也是按照这样的顺序进行遍历:
public static void preOrder (TreeNode root) {
if (root==null )return ;
System.out.print(root.value);
preOrder(root.left);
preOrder(root.right);
}
public static void main (String[] args) {
TreeNode tree=createTree();
preOrder(tree);
}
具体的遍历过程在上述的图中已经讲过啦,这里就不在论述~
(2) 中序遍历 中序遍历的遍历顺序是:根的左子树--->根节点--->根的右子树。对于每棵子树也是按照这样的顺序进行遍历:
public static void inOrder (TreeNode root) {
if (root==null )return ;
inOrder(root.left);
System.out.print(root.value);
inOrder(root.right);
}
public static void main (String[] args) {
TreeNode tree=createTree();
inOrder(tree);
}
(3) 后序遍历 后序遍历的遍历顺序是:根的左子树--->根的右子树--->根节点。对于每棵子树也是按照这样的顺序进行遍历:
public static void PostOrder (TreeNode root) {
if (root==null )return ;
PostOrder(root.left);
PostOrder(root.right);
System.out.print(root.value);
}
public static void main (String[] args) {
TreeNode tree=createTree();
PostOrder(tree);
}
(4) 三种遍历方式的特点 前序遍历 中序遍历 后序遍历 遍历顺序 根、左、右 左、根、右 左、右、根 遍历结果 ABDECFG DBEAFCG DEBFGCA 根节点位置 第一个 中间 最后一个
从表格中不难看出通过前序遍历、后续遍历,我们能快速的知道根节点是谁,那么则可以得出结论:
前序遍历和后序遍历的结果能够确定根 是谁,而中序遍历的根节点位置是在中间,说明根节点 (A) 的左边就是根结点的左子树元素 (DBE),根结点 (A) 的右边就是根结点的右子树元素 (FCG);
2.6 二叉树的基本操作
1. 获取树中结点的个数 public static int size (TreeNode root) {
if (root==null )return 0 ;
int left=size(root.left);
int right=size(root.right);
return left+right+1 ;
}
public static void main (String[] args) {
TreeNode tree=createTree();
System.out.println(size(tree));
}
2. 获得叶子结点个数 public static int getLeafTreeNodeCount (TreeNode root) {
if (root==null )return 0 ;
if (root.left==null &&root.right==null ){
return 1 ;
}
return getLeafTreeNodeCount(root.left)+getLeafTreeNodeCount(root.right);
}
public static void main (String[] args) {
TreeNode tree=createTree();
System.out.println(getLeafTreeNodeCount(tree));
}
3. 获得第 k 层结点的个数 public static int getKLevelTreeNodeCount (TreeNode root,int k) {
if (root==null ||k<1 )return 0 ;
if (k==1 )return 1 ;
return getKLevelTreeNodeCount(root.left,k-1 )+getKLevelTreeNodeCount(root.right,k-1 );
}
public static void main (String[] args) {
TreeNode tree=createTree();
System.out.println(getKLevelTreeNodeCount(tree,2 ));
}
4. 获取二叉树的高度 public static int getHeight (TreeNode root) {
if (root==null )return 0 ;
return Math.max(getHeight(root.left),getHeight(root.right))+1 ;
}
public static void main (String[] args) {
TreeNode tree=createTree();
System.out.println(getHeight(tree));
}
5. 检测值为 val 的元素是否存在 public static TreeNode findvalue (TreeNode root,char val) {
if (root==null )return null ;
if (root.value==val)return root;
TreeNode leftNode=findvalue(root.left,val);
if (leftNode!=null )return leftNode;
TreeNode rightNode=findvalue(root.right,val);
if (rightNode!=null )return rightNode;
return null ;
}
public static void main (String[] args) {
TreeNode tree=createTree();
System.out.println(findvalue(tree,'C' ).value);
}
6. 层序遍历 这里实现层序遍历需要借助队列来实现,如果对队列不熟悉的话可以看一下上一期博客:栈和队列
public static 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.value);
if (cur.left!=null ){
queue.offer(cur.left);
}
if (cur.right!=null ){
queue.offer(cur.right);
}
}
}
public static void main (String[] args) {
TreeNode tree=createTree();
levelOrder(tree);
}
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online