树形结构就是一种非常重要的非线性结构。在树形结构中数据元素之间具有一对多的逻辑关系,它反映了数据元素之间的层次关系,和一个数据元素可以有多个后继但最多只有一个前驱的特点。树形结构在现实中有很多实际应用。
一、 树
树是由n(n≥0)个结点所构成的有限集合,当n=0时,称为空树。
例:
常用术语:
1.树的结点
树的节点是由一个数据元素和关联其子树的边所组成。如图,有6个结点。
2. 结点的路径
路径的长度是指结点路径中所包含的分支数。如图,结点E的路径长度是2。
4.结点的度
结点的度是指该结点所拥有子树的数目。如图,结点C的度为2,结点E的度为0。
5. 树的度
树的度是指树中所有结点的度的最大值。如图,树的度为2。
6. 叶结点
树的度是指树中度为0的结点。如图,结点D、E、F都是叶结点。
7. 子结点 (孩子结点)
结点的子结点是指这个结点的子树的根结点。
8. 父结点 (双亲结点)
若树中的某个结点有孩子结点,则这个结点就称为孩子结点的父结点。
9. 兄弟结点
兄弟结点是指具有同一双亲的结点。如图,结点B、C是兄弟结点。
10. 结点的层次
规定树中根结点的层次为0,则其它结点的层次是其双亲结点的层次数加1。
11. 树的深度
树地深度是指树中所有结点的层次数的最大值加1。
12. 森林
森林是指由m(m≥0)棵互不相交的树所构成的集合。
二、 二叉树
1. 二叉树是一种特殊的树,它的每个结点最多只有两棵子树,并且这两棵子树也是二叉树。
当n=0时,二叉树为空树;当n≥0时,二叉树由根节点和左右子树构成。
2. 满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
即如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
3.完全二叉树
叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
三、 二叉树的性质
1. 二叉树中第i(i≥0)层上的结点数最多为2^i
2. 深度为h(h≥1)的二叉树中最多有2^h-1个结点
3. 对于任何一棵二叉树,若其叶结点的个数为n0,度为2的结点个数为n2,则有n0=n2+1
4. 具有n个结点的完全二叉树,其深度为[ log2n ]+1
四、 二叉树的存储结构
1. 二叉树的存储实现方法有多种,主要有顺序存储和链式存储两大类。
2. 在二叉链表结构中,二叉树的每一个结点有3个域:数据域、左孩子域和右孩子域。
其中,数据域用来存放结点的值,左、右孩子域分别用来存放结点的左、右孩子结点党的存储地址。
五、 二叉树的实现
二叉链式存储结构是二叉树最常用的存储结构。
代码如下:
public class BinTree {
private Node root; //根节点
private static int index=0; //记录字符串的索引值(先序创建二叉树)
public BinTree()
{
this.root=null;
}
public BinTree(Node root)
{
this.root=root;
}
//根据字符串先序创建二叉树
public BinTree(String preStr)
{
char c=preStr.charAt(index++);
if(c!='#')
{
root=new Node(c);
root.lchild=new BinTree(preStr).root;
root.rchild=new BinTree(preStr).root;
}
else
root=null;
}
//获取树根
public Node getRoot()
{
return root;
}
//获取结点的父节点
public Node getParent(Node current, Node r)
{
if(r==null)
return null;
if(r.lchild==current || r.rchild==current)
return r;
Node lNode=getParent(current, r.lchild);
Node rNode=getParent(current, r.rchild);
if(lNode==null)
return rNode;
if(rNode==null)
return lNode;
return r;
}
//获取左结点
public Node getLchild(Node r)
{
return (r!=null)?r.lchild:null;
}
//获取右结点
public Node getRchild(Node r)
{
return (r!=null)?r.rchild:null;
}
//查找所在结点
public Node searchNode(Node r, Object x)
{
if(r!=null)
{
if(r.data.equals(x))
return r;
else
{
Node q=searchNode(r.lchild, x);
return q!=null? q:searchNode(r.rchild, x);
}
}
return null;
}
//计算结点总个数
public int countNode(Node r)
{
if(r==null)
return 0;
else
return countNode(r.lchild)+countNode(r.rchild)+1;
}
//求树的深度
public int getDepth(Node r)
{
if(r==null)
return 0;
else
{
int left=getDepth(r.lchild);
int right=getDepth(r.rchild);
return left>right?(left+1):(right+1);
}
}
//先序递归
public void preRootTraverse(Node r)
{
if(r!=null)
{
System.out.print(r.data+" ");
preRootTraverse(r.lchild);
preRootTraverse(r.rchild);
}
}
//先序非递归
public void preRootTraverse()
{
Node r=root;
if(r!=null)
{
Stack<Node> stack=new Stack<Node>();
stack.push(r);
while(!stack.isEmpty())
{
r=(Node)stack.pop();
System.out.print(r.data+" ");
while(r!=null)
{
if(r.lchild!=null)
System.out.print(r.lchild.data+" ");
if(r.rchild!=null)
stack.push(r.rchild);
r=r.lchild;
}
}
}
}
//中序递归
public void inRootTraverse(Node r)
{
if(r!=null)
{
inRootTraverse(r.lchild);
System.out.print(r.data+" ");
inRootTraverse(r.rchild);
}
}
//中序非递归
public void inRootTraverse()
{
Node r=root;
if(r!=null)
{
Stack<Node> stack=new Stack<Node>();
stack.push(r);
while (!stack.isEmpty())
{
while(stack.peek()!=null)
{
Node q=(Node)stack.peek();
stack.push(q.lchild);
}
stack.pop();
if(!stack.isEmpty())
{
r=(Node)stack.pop();
System.out.print(r.data+" ");
stack.push(r.rchild);
}
}
}
}
//后序递归
public void postRootTraverse(Node r)
{
if(r!=null)
{
postRootTraverse(r.lchild);
postRootTraverse(r.rchild);
System.out.print(r.data+" ");
}
}
//后序非递归
public void postRootTraverse()
{
Node r=root;
if(r!=null)
{
Stack<Node> stack=new Stack<Node>();
stack.push(r);
Boolean flag;
Node q=null;
while(!stack.isEmpty())
{
while (stack.peek()!=null)
{
Node t=(Node)stack.peek();
stack.push(t.lchild);
}
stack.pop();
while(!stack.isEmpty())
{
r=(Node)stack.peek();
if(r.rchild==null || r.rchild==q)
{
System.out.print(r.data+" ");
stack.pop();
q=r;
flag=true;
}
else
{
stack.push(r.rchild);
flag=false;
}
if(!flag)
break;
}
}
}
}
//层次遍历
public void levelTraverse()
{
Node r=root;
if(r!=null)
{
ArrayDeque deque=new ArrayDeque();
deque.offer(r);
while (!deque.isEmpty())
{
r=(Node)deque.poll();
System.out.print(r.data+" ");
if(r.lchild!=null)
deque.offer(r.lchild);
if(r.rchild!=null)
deque.offer(r.rchild);
}
}
}
//判断两棵树是否相等
public boolean isEqual(Node t1, Node t2)
{
if(t1==null && t2==null)
return true;
if(t1!=null && t2!=null)
{
if(t1.data.equals(t2.data))
{
if(isEqual(t1.lchild, t2.rchild))
{
if(isEqual(t1.rchild, t2.rchild))
{
return true;
}
}
}
}
return false;
}
//打印树
public void printTree(Node r)
{
if(r==null)
return;
else if(r.lchild==null && r.rchild==null)
System.out.print(r.data);
else
{
System.out.print(r.data +"(");
printTree(r.lchild);
System.out.print(",");
printTree(r.rchild);
System.out.print(")");
}
}
//例子建立二叉树
public static BinTree createBinTree()
{
Node d=new Node('D');
Node g=new Node('G');
Node h=new Node('H');
Node e=new Node('E', g,null);
Node f=new Node('F',null, h);
Node b=new Node('B', d, e);
Node c=new Node('C', f, null);
Node a=new Node('A', b, c);
return new BinTree(a);
}
//顺序建立二叉树
public static Node createBinTree(String seqStr,int i)
{
Node r=null;
if(i<seqStr.length())
{
char c=seqStr.charAt(i);
if(c!='#')
{
r = new Node(c);
r.lchild = createBinTree(seqStr, 2 * i + 1);
r.rchild = createBinTree(seqStr, 2 * i + 2);
}
}
return r;
}
public static void main(String[] args)
{
/*建立二叉树(例子)
BinTree tree=BinTree.createBinTree();
*/
/*顺序建立二叉树
String preStr="ABCDEF###G##H";
Node r=BinTree.createBinTree(preStr,0);
BinTree tree=new BinTree(r);
*/
String preStr="ABD##EG###CF#H###"; //根据字符串先序建立二叉树
BinTree tree=new BinTree(preStr);
Node r=tree.getRoot(); //获取根节点
System.out.println("例子: A(B(D,E(G,)),C(F(,H),))");
System.out.println("根节点:"+tree.getRoot().data);
char c='B';
Node currNode=tree.searchNode(r,c);
Node currParentNode=tree.getParent(currNode,r);
Node currLchildNode=tree.getLchild(currNode);
Node currRchildNode=tree.getRchild(currNode);
System.out.print("B所在结点:"+currNode.data+", ");
System.out.print("B的父节点结点:"+currParentNode.data+", ");
System.out.print("B的左结点:"+currLchildNode.data+", ");
System.out.print("B的右结点:"+currRchildNode.data);
System.out.println();
System.out.println("树高: "+tree.getDepth(r));
System.out.println("树结点总个数: "+tree.countNode(r));
System.out.print("先序遍历(递归): ");
tree.preRootTraverse(r);
System.out.println();
System.out.print("先序遍历(非递归):");
tree.preRootTraverse();
System.out.println();
System.out.print("中序遍历(递归): ");
tree.inRootTraverse(r);
System.out.println();
System.out.print("中序遍历(非递归):");
tree.inRootTraverse();
System.out.println();
System.out.print("后序遍历(递归): ");
tree.postRootTraverse(r);
System.out.println();
System.out.print("后序遍历(非递归):");
tree.postRootTraverse();
System.out.println();
System.out.print("层序遍历(递归): ");
tree.levelTraverse();
System.out.println();
System.out.print("打印树: ");
tree.printTree(r);
System.out.println();
}
}
运行结果:
好不容易整完了,有点费时间,不过整理完后关于二叉树的东西都有条有序清晰起来,也方便过后回忆。
加油!(凡星逝水2018!)