树的相关概念
什么是树
树( T r e e Tree Tree)是 n n n ( n ≧ 0 n ≧ 0 n≧0 )个结点的有限集。 n = 0 n=0 n=0 时称为空树。在任意一颗非空树中:有且仅有一个特定的称为根的结点。当 n > 1 n>1 n>1 时,其余结点可分为 m m m ( m > 0 m > 0 m>0 ) 个互不相交的有限集 T 1 T1 T1、 T 2 T2 T2、 T 3 T3 T3……、 T m Tm Tm,其中每个集合本身又是一棵树,并且称为根的子树。
树的基本概念
二叉树
什么是二叉树
二叉树是 n n n ( n > = 0 n>=0 n>=0) 个结点的有限集合,该集合或者为空集(空二叉树)、或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树的特点
1.二叉树中每个结点最多有两颗子树,度没有超过 2 2 2 的。
2.左子树和右子树是有顺序的,不能颠倒。
满二叉树
在二叉树中,所有的分支节点都有左子树和右子树,并且所有的叶子都在同一层。
完全二叉树
1.叶子结点只能出现在最下面两层。
2.最下层的叶子一定集中在左部连续位置。
3.倒数第二层,若有叶子结点,一定在右部连续位置。
4.如果结点度为 1$ ,则该结点只有左孩子。
5.同样结点的二叉树,完全二叉树的深度最小。
二叉树的创建和嵌套打印
//结点类
public class TreeNode{
int data;//结点存放的数据
TreeNode left;//左孩子
TreeNode right;//右孩子
public TreeNode(int data,TreeNode left,TreeNOde right){
this.data = data;
this.left = left;
this.right = right;
}
}
import java.util.Scanner;
public class Tree{
TreeNode root;//整棵树的根节点
Scanner sc = new Scanner(System.in);
public Tree(){
root = null;
}
public TreeNode createBinaryTree(){//树的创建
TreeNode t;//当前树的根节点
int x = sc.nextInt();
if(x==0) t=null;
else{
t = new TreeNode();
t.data = x;
t.left = createBinaryTree();
t.right = createBinaryTree();
}
return t;
}
public void printTree(TreeNode t){//树的打印
if(t!=null){
System.out.print(t.data);
if(t.left!=null || t.right!=null){
System.out.print("(");
printTree(t.left);
if(t.right!=null) System.out.print(",");
printTree(t.left);
System.out.print(")");
}
}
}
}
前中后序层次遍历
前序遍历
思路:对于每个结点,优先处理结点本身,再处理它的左孩子,最后处理它的右孩子。
此图结果为: A B D G H C E I F ABDGHCEIF ABDGHCEIF
public void preOrder(TreeNode root){
if(root!=null){
System.out.print(root.data+" ");
preOrder(root.left);
preOrder(root.right);
}
}
中序遍历
思路:对于每个结点,优先处理它的左孩子,再处理它本身,最后处理它的右孩子。
此图结果为: G D H B A E I C F GDHBAEICF GDHBAEICF
public void midOrder(TreeNode root){
if(root!=null){
midOrder(root.left);
System.out.print(root.data+" ");
midOrder(root.right);
}
}
后序遍历
思路:对于每个结点,优先处理它的左节点,再处理它的右节点,最后处理它本身。
此图结果为: G H D B I E F C A GHDBIEFCA GHDBIEFCA
public void postOrder(TreeNode root){
if(root!=null){
postOrder(root.left);
postOrder(root.right);
System.out.print(root.data+" ");
}
}
层次遍历
思路:广度优先搜索;借助一个队列;先将二叉树根结点入队,然后出队,访问出队结点,若它有左子树,则将左子树根结点入队;若它有右子树,则将右子树根结点入队。然后出队,访问出队结…如此反复,直至队列为空。
此图结果为: A B C D E F G H I ABCDEFGHI ABCDEFGHI
public void levelOrder(TreeNode t){
Queue<TreeNode> queue = new LinkedList<>();
if(t==null) return;
queue.offer(t);
while(!queue.isEmpty()){
TreeNode head = queue.poll();
System.out.print(head.data);
if(head.left!=null)
queue.offer(head.left);
if(head.right!=null)
queue.offer(head.right);
}
}
求二叉树深度
public int treeDepth(TreeNode root){
if(root==null) return 0;//此结点不存在
return Math.max(treeDepth(root.left),treeDepth(root.right))+1;
}
求二叉树叶子结点个数
public int TreeLeaf(TreeNode root){
if(root==null) return 0;
if(root.left==null && root.right==null) return 1;//此结点没有孩子,表示此结点为叶子结点
else return treeLeaf(root.left) + treeLeaf(root.right);
}
重建二叉树
思路:
1.前序遍历为:根,{左子树},{右子树};可得,前序遍历的第一个结点为根结点;
2.中序遍历为:{左子树},根,{右子树};可得,结点的左侧为它的左孩子树,右侧为它的右孩子树;
3.重复此过程,重建此二叉树(求后序遍历结果);
以此树为例:
1.前序遍历为 A B D E H C F G ABDEHCFG ABDEHCFG,中序遍历为 D B H E A F C G DBHEAFCG DBHEAFCG;
2.前序遍历的第一个点( A A A )一定是根节点,那么中序遍历中, A A A 左边的部分( D B H E DBHE DBHE)为 A A A 的左子树,右边的部分( F C G FCG FCG )为 A A A 的右子树;
3.每一个子树也都是一个完整的树,那么对于树( B D E H BDEH BDEH), B B B 是这个子树的根节点,这个子树的左子树为( D D D),右子树为( E H EH EH);对于树( C F G CFG CFG), C C C 是这个子树的根节点,这个子树的左子树为 F F F,右子树为 G G G;
4.重复此过程,直至每一个子树都检索完成为止,此时,树其实已经重建出来了,后序遍历也可得到(对于每一个子树,优先输出左子树,输出右子树,最后输出根节点);
public static String f(String pre,String mid){//前序遍历结果,中序遍历结果
if(pre.length()==0) return "";
else if(pre.length==1) return pre;
else{
int pos = mid.indexOf(pre.charAt(0));
String left = f(pre.substring(1,pos+1),mid.substring(0,pos));
String right = f(pre.substring(pos+1),mid.substring(pos+1));
return left+right+pre.charAt(0);
}
}
二叉排序树
二叉排序树(也称二叉查找树)或者是一棵空树,或者是具有下列特性的二叉树:
若左子树非空,则左子树上所有结点的值均小于根结点的值。
若右子树非空,则右子树上所有结点的值均大于根结点的值。
左、右子树也分别是一棵二叉排序树。
根据二叉排序树的定义,左子树结点值
<
<
< 根结点值
<
<
< 右子树结点值,所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。
此图二叉排序树的中序遍历序列为 123468 123468 123468 。