二叉树概念
概念
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看 起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
下面是一些简单的概念。
结点的度:一个结点含有子树的个数称为该结点的度;
树的度:一棵树中,所有结点度的最大值称为树的度;
叶子结点或终端结点:度为0的结点称为叶结点;
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;
根结点:一棵树中,没有双亲结点的结点;
结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
树的高度或深度:树中结点的最大层次;
非终端结点或分支结点:度不为0的结点;
兄弟结点:具有相同父结点的结点互称为兄弟结点;
堂兄弟结点:双亲在同一层的结点互为堂兄弟;
结点的祖先:从根到该结点所经分支上的所有结点;
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。
森林:由m(m>=0)棵互不相交的树组成的集合称为森林 。
特点
1.根节点没有前驱节点,可以通过根节点来遍历这棵树。
2.除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <= m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。这是什么意思呢?其实就是一棵树可以分为多个子树,根节点以外的节点又可以分别看成一棵树。
3.树是递归定义的。这句话指的是树这种数据结构可以通过递归的方式来定义和构建。
代码实现
1.定义一个二叉树的类
一个二叉树,每个节点包含有自己的值,指向左右孩子,由此来定义一个树类。
public class BinaryTree {
//定义树的节点
public class TreeNode{
//节点带的值
public char val;
//左孩子
public TreeNode left;
//右孩子
public TreeNode right;
//实例化时只需要传递值,因为不知道节点左右孩子的地址
public TreeNode(char val) {
this.val = val;
}
}
2.创建一个简单的二叉树
这里使用穷举的方式创建了一颗二叉树,后面会讲到使用更简单的方式创建二叉树。
将头节点A作为根节点返回。
public 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');
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;
return A;
}
这棵二叉树的样子为:
3.二叉树的前序遍历,中序遍历,后序遍历
三种遍历的思想
前序遍历(Preorder Traversal): 在前序遍历中,首先访问根节点,然后按照左孩子、右孩子的顺序递归遍历子树。可以用以下递归方式进行前序遍历:先访问根节点,然后递归前序遍历左子树,最后递归前序遍历右子树。
递归遍历上图中的树,首先从根节点A出发(打印节点值),遍历A的左子树,最后遍历右子树C。
这里我用图来描述一下前序遍历的过程,中序遍历和后序遍历与前序遍历相似,不过多画图了。
中序遍历(Inorder Traversal): 在中序遍历中,先递归中序遍历左子树,然后访问根节点,最后递归中序遍历右子树。中序遍历的顺序是左子树 -> 根节点 -> 右子树。
递归遍历上图中的树,首先遍历A的左子树,打印节点值 ,最后遍历右子树C。
后序遍历(Postorder Traversal): 在后序遍历中,先递归后序遍历左子树,然后递归后序遍历右子树,最后访问根节点。后序遍历的顺序是左子树 -> 右子树 -> 根节点。
递归遍历上图中的树,首先遍历A的左子树,遍历右子树C ,最后打印节点值。
实现(递归实现)
在进行遍历之前,首先判断节点是否是空节点,如果为空,直接返回,这也是递归的结束条件,当向下递归时遇到的节点为空,则直接return返回了,递归结束,返回上个函数中。
1.前序遍历
public void preOrder(TreeNode root) {
//节点为空直接返回
if(root == null) {
return;
}
//打印根节点
System.out.print(root.val+" ");
//遍历左子树
preOrder(root.left);
//遍历右子树
preOrder(root.right);
}
2.中序遍历
public void inOrder(TreeNode root) {
//节点为空直接返回
if(root == null) {
return;
}
//先遍历左子树
inOrder(root.left);
//打印节点值
System.out.print(root.val+" ");
//遍历右子树
inOrder(root.right);
}
3.后序遍历
public void lastOrder(TreeNode root) {
//节点为空直接返回
if (root == null) {
return;
}
//遍历左子树
lastOrder(root.left);
//遍历右子树
lastOrder(root.right);
//打印节点值
System.out.print(root.val+" ");
}