06.Java数据结构与算法之~二叉树
树
树(Tree)是n(n >= 0)个结点的有限集。n = 0时称为空树。
在任意一颗非空树中,有且仅有一个特定的称为根(Root)的结点。
其余结点可分为m(m > 0)个互不相交的有限集 T1、T2、、、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)
以下不是树
原因: E既是D的子集又是C的子集,违反了树的概念!
结点的度
结点拥有的子树数称为结点的度。度为0的结点称为叶子结点或终端结点。度不为0的结点称为非终端结点或分支结点。除根结点以外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。
层次与深度
结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。若某结点在第1层,则其子树的根就在 i + 1 层。其双亲在同一层的结点互为堂兄弟。显然图中的D、E、F是堂兄弟,而G、H、I、J也是。树中结点的最大层次称为树的深度(Deph)或高度,当前树的深度为4。
有序与无序树
如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称无序树。
二叉树
为什么需要树这种数据结构?
数组存储方式的分析:
优点:通过下标方式访问元素,速度快。对于有序数组,还可以用二分查找提高检索速度
缺点:如果要检索某个具体值,或者插入删除值会整体移动,效率较低
链式存储方式的分析:
优点:在一定程度上对数组存储方式有优化,比如,插入一个数值结点只需要将插入结点连接到链表中即可,删除也只需要将前一个结点指向后一个结点不需要整体移动,因此效率好
缺点:在进行检索时,效率依然很低。因为需要从头遍历
树存储方式分析:
比如二叉排序树(Binary sort tree)既可以保证数据的检索速度,又可以保证插入、删除、修改的速度
什么是二叉树?
每个节点最多只能有两个子节点的一种形式称为二叉树
二叉树的子节点分为左节点和右节点
斜树
所有节点都只有左子树的二叉树称为左斜树,只有右子树的二叉树称为右斜树。总之统称为斜树
满二叉树
在一颗二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
二叉树遍历代码实现
定义Tree接口
public interface Tree {
//构建树
void CreateBinaryTree(Object tree, Object left, Object right);
//先序遍历
void PreOrder();
//中序遍历
void InfixOrder();
//后序遍历
void PostOrder();
}
编写BinaryTree二叉树实现类
public class BinaryTree implements Tree{
private BinaryTree left; //左子树
private BinaryTree right; //右子树
private Object root; //根节点
//-------构造传值-------
public BinaryTree(Object data){
root = data;
}
@Override
//-------构建树------- 为了兼容接口统一Object
public void CreateBinaryTree(Object tree, Object left, Object right){
//强制转换
BinaryTree Tree = (BinaryTree) tree;
Tree.left = (BinaryTree)left;
Tree.right = (BinaryTree)right;
}
//-------先序遍历-------
@Override
public void PreOrder() {
//判断二叉树是否为空
if(root != null){
System.out.print(root + " ");
//判断左子节点是否为空
if(left != null){
left.PreOrder();
}
if(right != null){
right.PreOrder();
}
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
//-------中序遍历-------
@Override
public void InfixOrder() {
//判断二叉树是否为空
if(root != null){
//判断左子节点是否为空
if(left != null){
left.InfixOrder();
}
System.out.print(root + " ");
if(right != null){
right.InfixOrder();
}
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
//-------后序遍历-------
@Override
public void PostOrder() {
//判断二叉树是否为空
if(root != null){
//判断左子节点是否为空
if(left != null){
left.PostOrder();
}
if(right != null){
right.PostOrder();
}
System.out.print(root + " ");
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
}
测试:
public static void main(String[] args) {
Tree A = new BinaryTree("A");
Tree B = new BinaryTree("B");
Tree C = new BinaryTree("C");
Tree D = new BinaryTree("D");
Tree E = new BinaryTree("E");
Tree F = new BinaryTree("F");
Tree G = new BinaryTree("G");
A.CreateBinaryTree(A,B,C); //定义A的两个子节点
A.CreateBinaryTree(B,D,E); //定义B的两个子节点
A.CreateBinaryTree(C,F,G); //定义C的两个子节点
System.out.println("先序遍历");
A.PreOrder();
System.out.println("\n中序遍历");
A.InfixOrder();
System.out.println("\n后序遍历");
A.PostOrder();
}