树
1、树形结构
1.1 树的定义
树是一种数据结构,它是由n(n≥1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。
1.2 树的基本概念
- 空集合也是树,称为空树。空树中没有节点;
- 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
- 节点的度:一个节点含有的子节点的个数称为该节点的度;
- 叶节点或终端节点:度为0的节点称为叶节点;
- 非终端节点或分支节点:度不为0的节点;
- 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
- 兄弟节点:具有相同父节点的节点互称为兄弟节点;
- 树的度:一棵树中,最大的节点的度称为树的度;
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
- 树的高度或深度:树中节点的最大层次;
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟;
- 节点的祖先:从根到该节点所经分支上的所有节点;
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙;
- 森林:由 棵互不相交的树的集合称为森林。
1.3 树的表示形式(双亲表示法)
class Node {
int value; // 树中存储的数据
Node firstChild; // 第一个孩子引用
Node nextBrother; // 下一个兄弟引用
}
2. 二叉树(重点)
2.1 二叉树的定义
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分 。
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点 。
2.2 二叉树的基本形态
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有以下五种基本形态:
上图给出了几种特殊的二叉树形态,从左往右依次是:空二叉树、只有根节点的二叉树、只有左子树、只有右
子树、完全二叉树,一般二叉树都是由上述基本形态结合而形成的。
2.3 特殊的二叉树
**满二叉树:**如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
**完全二叉树:**深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树 。
完全二叉树的特点是叶子结点只可能出现在层序最大的两层上,并且某个结点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1 。
2.4 二叉树的表示形式(孩子表示法)
// 孩子表示法
class TreeNode {
int val; // 数据域
TreeNode left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
TreeNode right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
2.5 二叉树的遍历
遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:访问结点本身(N),遍历该结点的左子树(L),遍历该结点的右子树(R)。
2.5.1 前序遍历
若二叉树非空,则依次执行如下操作,访问根结点—>根的左子树—>根的右子树
代码如下:
public void preOrder(TreeNode root)
{
if (root == null)//如果根节点为空,直接返回
{
return;
}
System.out.print(root.val + " ");//打印根节点的值
preOrder(root.left);//递归打印左子树
preOrder(root.right);//递归打右左子树
}
分析如下:
2.5.2 中序遍历
若二叉树非空,则依次执行如下操作,访问根的左子树—>根结点—>根的右子树
代码如下:
public void preOrder(TreeNode root)
{
if (root == null)//如果根节点为空,直接返回
{
return;
}
preOrder(root.left);//递归打印左子树
System.out.print(root.val + " ");//打印根节点的值
preOrder(root.right);//递归打右左子树
}
2.5.3 后序遍历
若二叉树非空,则依次执行如下操作,访问根的左子树—>根的右子树—>根结点
代码如下:
public void preOrder(TreeNode root)
{
if (root == null)//如果根节点为空,直接返回
{
return;
}
preOrder(root.left);//递归打印左子树
preOrder(root.right);//递归打右左子树
System.out.print(root.val + " ");//打印根节点的值
}