1. 程式人生 > >二叉樹(Binary Tree)詳解

二叉樹(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