二叉樹(Binary Tree)詳解

二叉樹本身就是遞歸定義的(wikipedia)

To actually define a binary tree in general, we must allow for the possibility that only one of the children may be empty. An artifact, which in some textbooks is called an extended binary tree is needed for that purpose. An extended binary tree is thus recursively defined as:

1.the empty set is an extended binary tree

2.if T1 and T2 are extended binary trees, then denote by T1 • T2 the extended binary tree obtained by adding a root r connected to the left to T1 and to the right to T2 by adding edges when these sub-trees are non-empty.

就是說考慮空集也是“擴展二叉樹”,通過一個樹節點節點將兩個“擴展二叉樹”分別作爲左右子節點後,以該樹節點爲根節點構成一棵“擴展二叉樹”。

 

二叉樹類型:滿二叉樹、完全二叉樹、完美二叉樹、平衡二叉

性質:太多了!!!

存儲二叉樹節點的方法:

1.節點和引用,這個自不必說。

2.數組:二叉樹以隱式廣度優先搜索順序存儲在數組中,這種方法節省兩個左右子節點引用的內存。

對於以0爲索引開頭的數組,數組索引值爲i的節點,它的左右子節點的索引分別爲2i+1,2i+2,而它的父節點數組索引[(i-1)/2]

對於以1爲索引開頭的數組,數組索引值爲i的節點,它的左右子節點的索引分別爲2i,2i+1,而它的父節點數組索引[i/2]

存儲稠密並且更好的本地引用(數組索引速度快),然而這種存儲方法耗費的空間複雜度爲O(2^h-n)(深度h,節點數爲n的樹)

                                                         

直接上代碼:

//二叉樹的二叉鏈表樹用根節點來表示
public class BinaryTree<T>{
	
	public BinaryNode<T> root;
	public BinaryTree()
	{
		this.root=null;
	}
	
	public BinaryTree(BinaryNode<T> root)
	{
		this.root=root;
	}
	
	/*
	 先根遍歷和中根遍歷兩種次序可以唯一確定二叉樹,perlist和inlist長度爲n,序號爲0~n-1
	 先根遍歷序列prelist的perlist[0]爲根節點,在中根遍歷序列的inlist中尋找值爲perlist[0]的節點,序號爲i
	 在inlist中i左邊0,i-1爲左子樹,i+1,n爲右子樹
	 左子樹的先根遍歷序列爲prelist[1],...,prelist[i]
	 左子樹的中根遍歷序列爲inlist[0],...inlist[i-1]
	 右子樹的先根遍歷序列爲prelist[i+1],...prelist[n-1]
	 右子樹的中根遍歷序列inlist[i+1],...,inlist[n-1]
	 */
	public BinaryTree(T[] prelist,T[] inlist)
	{
		this.root=create(prelist,inlist,0,0,prelist.length);
	}
	
	public BinaryNode<T> create(T[] prelist,T[] inlist,int preStart,int inStart,int n )
	{
		if(n<=0)
			return null;
		T e=prelist[preStart];
		BinaryNode<T> p=new BinaryNode<T>(e);
		
		int i=0;
		while(i<n && !inlist[i+inStart].equals(e))
			i++;
		p.left=create(prelist,inlist,preStart+1,inStart,i);
		p.right=create(prelist,inlist,preStart+i+1,inStart+i+1,n-1-i);
		return p;
	}
	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return this.root==null;
	}

	@Override
	public int count() {
		// TODO Auto-generated method stub
		return count(this.root);
	}
	public int count(BinaryNode<T> p) 
	{
		if(p==null)
			return 0;
		return 1+count(p.left)+count(p.right);
	}
	@Override
	public int height() {
		// TODO Auto-generated method stub
		return height(this.root);
	}

	//遞歸調用height求當前節點的高度
	public int height(BinaryNode<T> p)
	{
		if(p==null)
			return 0;
		int lcount=height(p.left);
		int rcount=height(p.right);
		return (lcount>=rcount)?lcount+1:rcount+1;
	}
	@Override
	public void preOrder() {
		//先根次序遍歷:訪問根節點,遍歷左子樹,遍歷右子樹 TODO Auto-generated method stub
		System.out.print("先根次序遍歷二叉樹");
		preOrder(root);
		System.out.println();
	}

	public void preOrder(BinaryNode<T> p)
	{
		if(p!=null)
		{
			System.out.print(p.data.toString()+" ");
			preOrder(p.left);
			preOrder(p.right);
		}
	}
	
	/*用非遞歸先根遍歷以node爲根節點的(子)樹
	*在二叉樹先序遍歷非遞歸算法中,先將根結點壓棧,在棧不爲空的時候執行循環:讓棧頂元素p出棧,訪問棧頂元素p,
	*如果p的右孩子不爲空,則讓其右孩子先進棧,如果p的左孩子不爲空,則再讓其左孩子進棧
	*(注意:進棧順序一定是先右孩子,再左孩子)。
	*/
	public void preOrderNoRecursive(BinaryNode<T> node)
	{
		LinkedStack<BinaryNode<T>> stack=new LinkedStack<BinaryNode<T>>();
		BinaryNode<T> p=node;
		//停止while循環的條件是棧爲空並且p指向null
		while(!stack.isEmpty() || p!=null)
		{
			while(p!=null)
			{
				System.out.print(p.data);
				stack.push(p);//入棧操作表示訪問該節點
				p=p.left;
			}
			if(!stack.isEmpty())
			{
				p=stack.getTop();
				stack.pop();
				p=p.right;
			}
		}
	}
	
	public void preOrderNoRecursive2(BinaryNode<T> node)
	{
		LinkedStack<BinaryNode<T>> stack=new LinkedStack<BinaryNode<T>>();
		BinaryNode<T> p=node;
		while(!stack.isEmpty() || p!=null)
		{
			if(p!=null)
			{
				System.out.print(p.data);
				stack.push(p);
				p=p.left;
			}
			else
			{
				p=stack.getTop();
				stack.pop();
				p=p.right;
			}
		}
	}
	
	@Override
	public void inOrder() {
		//中根次序遍歷:遍歷左子樹,訪問根節點,遍歷右子樹 TODO Auto-generated method stub
		System.out.print("中根次序遍歷二叉樹");
		inOrder(root);
		System.out.println();
	}

	public void inOrder(BinaryNode<T> p)
	{
		if(p!=null)
		{
			preOrder(p.left);
			System.out.print(p.data.toString()+" ");
			preOrder(p.right);
		}
	}
	
	//用非遞歸中根遍歷以node爲根節點的(子)樹
	public void inOrderNoRecursive(BinaryNode<T> node)
	{
		System.out.println("非遞歸中根遍歷: ");
		LinkedStack<BinaryNode<T>> stack=new LinkedStack<BinaryNode<T>>();
		BinaryNode<T> p=node;
		while(!stack.isEmpty() || p!=null )
		{
			if(p!=null)
			{
				stack.push(p);
				p=p.left;
			}
			else
				{
				p=stack.pop();
				System.out.print(p.data+" ");
				p=p.right;
				}
		}
	}
	
	
	
	@Override
	public void postOrder() {
		// 後根次序遍歷:遍歷左子樹,遍歷右子樹,訪問根節點TODO Auto-generated method stub
		System.out.print("後根次序遍歷二叉樹");
		postOrder(root);
		System.out.println();
	}

	public void postOrder(BinaryNode<T> p) 
	{
		if(p!=null)
		{
			postOrder(p.left);
			postOrder(p.right);
			System.out.print(p.data.toString()+" ");
		}
	}
	
	//對於非遞歸後根遍歷,使用順序棧比
	public void postOrderNoRecursive(BinaryNode<T> node)
	{
		System.out.println("非遞歸後根遍歷: ");
		SeqStack<BinaryNode<T>> stack=new SeqStack<BinaryNode<T>>();
		BinaryNode<T> p=node;
		int[] tag=new int[this.count()];
		//停止while循環的條件是棧爲空並且p指向null
		while(!stack.isEmpty() || p!=null)
		{
			while(p!=null)
			{
				stack.push(p);
				tag[stack.getTopIndex()]=0;
				p=p.left;
			}
			while(!stack.isEmpty() && tag[stack.getTopIndex()]==1)
			{
				System.out.print(stack.pop());
			}
			if(!stack.isEmpty())
			{
				p=stack.getTop();
				tag[stack.getTopIndex()]=1;
				p=p.right;
			}
		}
	}
	
	public void postOrderNoRecursive2(BinaryNode<T> node)
	{
		if(node==null)
			return;
		LinkedStack<BinaryNode<T>> stack=new LinkedStack<BinaryNode<T>>();
		stack.push(node);
		BinaryNode<T> lastPop=node;
		while(!stack.isEmpty())
		{
			BinaryNode<T> top =stack.getTop();
			if(top.left!=null && top.left!=lastPop && top.right!=lastPop)
				stack.push(top.left);
			else if(top.right!=null && top.right!=lastPop && (top.left==lastPop || top.left==null))
			{
				stack.push(top.right);
			}
			else
			{
				stack.pop();
				lastPop=top;
				System.out.print(top.data);
			}
		}
	}
	
	public String toGenListString()
	{
		return "二叉樹的廣義表形式"+this.toGenListString(this.root);
	}
	
	public String toGenListString(BinaryNode<T> node)
	{
		if(node==null)
			return "^";
		String str=node.data.toString();
		if(node.left!=null || node.right!=null)
			str+="("+this.toGenListString(node.left)+","+this.toGenListString(node.right)+")";
		return str;
	}
	
	
	public void levelOrder(BinaryNode<T> node) {
		// TODO Auto-generated method stub
		LinkedQueue<BinaryNode<T>> q=new LinkedQueue<BinaryNode<T>>();
		BinaryNode<T> p=node;
		q.enqueue(p);
		while(!q.isEmpty())
		{
			p=q.dequeu();
			System.out.print(p.data.toString());
			if(p.left!=null)
				q.enqueue(p.left);
			if(p.right!=null)
				q.enqueue(p.right);
		}
	}

	@Override
	public void levelOrder()
	{
		levelOrder(this.root);
	}
	
	@Override
	public BinaryNode<T> search(T key) {
		// TODO Auto-generated method stub
		return search(this.root,key);
	}

	public BinaryNode<T> search(BinaryNode<T> p,T key)
	{
		if(p==null||key==null)
			return null;
		if(p.data.equals(key))
			return p;
		BinaryNode<T> find=search(p.left,key);
		if(find==null)
			find=search(p.right,key);
		return find;
	}
	
	@Override
	public BinaryNode<T> getParent(BinaryNode<T> node) {
		// TODO Auto-generated method stub
		return getParent(this.root,node);
	}

	//查找以p爲根的子樹中節點node的父節點
	public BinaryNode<T> getParent(BinaryNode<T> p,BinaryNode<T> node)
	{
		if(p==null)
			return null;
		if(p.left==node||p.right==node)
			return p;
		BinaryNode<T> find=getParent(p.left,node);
		if(find==null)
			find=getParent(p.right,node);
		return find;
	}
	
	@Override
	public void insertRoot(T x) {
		// TODO Auto-generated method stub
		BinaryNode<T> new_root=new BinaryNode<T>(x);
		new_root.left=this.root;	
	}

	//插入x作爲節點p的左(右)子節點,如果p節點已經存在對應的左(右)節點,則原左(右)節點作爲插入節點的左(右)子節點
	@Override
	public BinaryNode<T> insertChild(BinaryNode<T> p, T x, boolean leftChild) {
		// TODO Auto-generated method stub
		if(p==null || x==null)
			return null;
		BinaryNode<T> new_node=new BinaryNode<T>(x);
		if(leftChild)
		{
			if(p.left==null)
				p.left=new_node;
			else
			{
				new_node.left=p.left;
				p.left=new_node;
			}
		}
		else
		{
			if(p.right==null)
				p.right=new_node;
			else
			{
				new_node.right=p.right;
				p.right=new_node;
			}
		}
		return new_node;
	}

	//刪除節點p的左(右)子節點,這裏規定將以p的左(右)子節點爲根節點的樹全部刪去
	@Override
	public void removeChild(BinaryNode<T> p, boolean leftChild) {
		// TODO Auto-generated method stub
		if(p!=null)
		{
			if(leftChild)
				p.left=null;
			else
				p.right=null;
		}
	}

	@Override
	public void removeAll() {
		// TODO Auto-generated method stub
		this.root=null;
	}
	
	public static void main(String[] args)
	{
		BinaryNode<String> n7=new BinaryNode<String>("H");
		BinaryNode<String> n6=new BinaryNode<String>("G");
		BinaryNode<String> n5=new BinaryNode<String>("F");
		BinaryNode<String> n4=new BinaryNode<String>("E");
		BinaryNode<String> n3=new BinaryNode<String>("D",n7,null);
		BinaryNode<String> n2=new BinaryNode<String>("C",n5,n6);
		BinaryNode<String> n1=new BinaryNode<String>("B",n3,n4);
		BinaryNode<String> n0=new BinaryNode<String>("A",n1,n2);
		
		BinaryTree<String> tree=new BinaryTree<String>(n0);
		System.out.println(tree.height());
		System.out.println(tree.count());
		tree.preOrder();
		tree.inOrder();
		tree.postOrder();
		tree.preOrderNoRecursive(n0);
		System.out.println();
		tree.preOrderNoRecursive2(n0);
		System.out.println();
		tree.postOrderNoRecursive(n0);
		System.out.println();
		tree.postOrderNoRecursive(n2);
		System.out.println();
		tree.postOrderNoRecursive2(n0);
		System.out.println();
		System.out.println(tree.toGenListString());
		System.out.println();
		tree.levelOrder();
	}
}

打印結果如下:

4
8
先根次序遍歷二叉樹A B D H E C F G 
中根次序遍歷二叉樹B D H E A C F G 
後根次序遍歷二叉樹H D E B F G C A 
ABDHECFG
ABDHECFG
非遞歸後根遍歷: 
HDEBFGCA
非遞歸後根遍歷: 
FGC
HDEBFGCA
二叉樹的廣義表形式A(B(D(H,^),E),C(F,G))

ABCDEFGH

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章