【Java】 大話數據結構(9) 樹(二叉樹、線索二叉樹)

 

本文根據《大話數據結構》一書,對Java版的二叉樹、線索二叉樹進行了必定程度的實現html

另:java

二叉排序樹(二叉搜索樹) node

平衡二叉樹(AVL樹)算法

二叉樹的性質

性質1:二叉樹第i層上的結點數目最多爲 2{i-1} (i≥1)。數據結構

性質2:深度爲k的二叉樹至多有2{k}-1個結點(k≥1)。ide

性質3:在任意一棵二叉樹中,若終端結點的個數爲n0,度爲2的結點數爲n2,則n0=n2+1post

    證實提示:分支線總數=n0+n1+n2-1=n1+2×n2
測試

性質4:具備n個節點的徹底二叉樹的深度爲[log2n]+1。([ ]表明向下取整)this

    證實提示:假設深度爲k,則有2{k-1} -1<n≤2{k} -1。編碼

性質5:若是有一顆有n個節點的徹底二叉樹的節點按層次序編號,對任一層的節點i(1<=i<=n)有

    1.若是i=1,則節點是二叉樹的根,無雙親,若是i>1,則其雙親節點爲[i/2]

    2.若是2i>n那麼節點i沒有左孩子(葉子結點),不然其左孩子爲2i

    3.若是2i+1>n那麼節點沒有右孩子,不然右孩子爲2i+1

 

二叉鏈表的定義代碼

 

class BiTNode<E>{
	E data;
	BiTNode<E> lchild,rchild;		
	public BiTNode(E data) {
		this.data=data;
		this.lchild=null;
		this.rchild=null;
	}
}

public class BiTree<E> {
	
	private BiTNode<E> root;

	public BiTree() {
		root=null;
	}

        ...
}

  

  

二叉樹的遍歷

 

	/*
	 * 前序遍歷
	 */
	public void preOrder() {
		preOrderTraverse(root);
		System.out.println();
	}	
	private void preOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		System.out.print(node.data);
		preOrderTraverse(node.lchild);
		preOrderTraverse(node.rchild);
	}
	
	/*
	 * 中序遍歷
	 */
	public void inOrder() {
		inOrderTraverse(root);
		System.out.println();
	}	
	private void inOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		inOrderTraverse(node.lchild);
		System.out.print(node.data);		
		inOrderTraverse(node.rchild);
	}
	
	/*
	 * 後序遍歷
	 */
	public void postOrder() {
		postOrderTraverse(root);
		System.out.println();
	}	
	private void postOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		postOrderTraverse(node.lchild);				
		postOrderTraverse(node.rchild);
		System.out.print(node.data);
	}

  

 

二叉樹的創建

  《大話》一書中,6.9節關於二叉樹的創建以下:

  經過輸入AB#D##C##,能夠生成上述二叉樹,其C語言的實現算法以下:

  暫時能力有限,還不懂如何改成Java代碼。

  幾點疑問:1.exit(OVERFLOW)不是很清楚什麼意思;

       2.代碼中爲char類型,如何用於泛型?

         3.scanf()在Java中怎麼實現?用scanner嗎?程序如何知道輸入完「AB#D##C##」就結束二叉樹的構造呢?總的實現代碼(包括main部分)是怎麼樣的?

如下爲測試代碼遍歷的整體測試代碼:

package BiTree;

class BiTNode<E>{
	E data;
	BiTNode<E> lchild,rchild;		
	public BiTNode(E data) {
		this.data=data;
		this.lchild=null;
		this.rchild=null;
	}
}

public class BiTree<E> {
	
	private BiTNode<E> root;

	public BiTree() {
		//root=new BiTNode(null, null, null);
		root=null;
	}
	
	/*
	 * 前序遍歷
	 */
	public void preOrder() {
		preOrderTraverse(root);
		System.out.println();
	}	
	private void preOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		System.out.print(node.data);
		preOrderTraverse(node.lchild);
		preOrderTraverse(node.rchild);
	}
	
	/*
	 * 中序遍歷
	 */
	public void inOrder() {
		inOrderTraverse(root);
		System.out.println();
	}	
	private void inOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		inOrderTraverse(node.lchild);
		System.out.print(node.data);		
		inOrderTraverse(node.rchild);
	}
	
	/*
	 * 後序遍歷
	 */
	public void postOrder() {
		postOrderTraverse(root);
		System.out.println();
	}	
	private void postOrderTraverse(BiTNode<E> node) {
		if(node==null)
			return;
		postOrderTraverse(node.lchild);				
		postOrderTraverse(node.rchild);
		System.out.print(node.data);
	}
	
	/*
	 * 6.9 二叉樹的創建暫時不會,略
	 */
	
	public static void main(String[] args) {
		BiTree<String> aBiTree = new BiTree<String>();
		aBiTree.root=new BiTNode("A");
		aBiTree.root.lchild=new BiTNode("B");
		aBiTree.root.rchild=new BiTNode("C");
		aBiTree.root.lchild.rchild=new BiTNode("D");
		System.out.println("————前序————");
		aBiTree.preOrder();
		System.out.println("————中序————");
		aBiTree.inOrder();
		System.out.println("————後序————");
		aBiTree.postOrder();
	}			
}

  

————前序————
ABDC
————中序————
BDAC
————後序————
DBCA
BiTree

 

 線索二叉樹

  對一個有n個節點的二叉鏈表(如上圖),整表存在2n個指針域,但分支線只有n-1條,說明空指針域的個數爲2n-(n-1) = n+1個,浪費了不少的內存資源。 

  咱們能夠經過利用這些空指針域,存放節點在某種遍歷方式下的前驅和後繼節點的指針。咱們把這種指向前驅和後繼的指針成爲線索,加上線索的二叉鏈表成爲線索鏈表,對應的二叉樹就成爲「線索二叉樹(Threaded Binary Tree)」,以下圖所示。

  線索二叉樹的Java代碼以下:

 

package BiThrTree;

/**
 * 線索二叉樹
 * 包含二叉樹的中序線索化及其遍歷
 * @author Yongh
 *
 */
class BiThrNode<E>{
	E data;
	BiThrNode<E> lChild,rChild;
	boolean lTag,rTag;	
	public BiThrNode(E data) {
		this.data=data;	
		//tag都先定義成左右孩子指針。
		lTag=false;  //其實把Tag定義爲IsThread更好
		rTag=false;
		lChild=null;
		rChild=null;
	}
}

public class BiThrTree<T> {
	BiThrNode<T> root; 
	boolean link=false,thread=true;
	
	public BiThrTree() {
		root=null;
	}
			
	/*
	 * 中序線索化二叉樹
	 * 即:在遍歷的時候找到空指針進行修改。
	 */
	BiThrNode<T> pre;	//線索化時記錄的前一個結點
	
	public void inThreading() {
		inThreading(root);
	}
	private void inThreading(BiThrNode<T> p) {
		if(p != null) {
			inThreading(p.lChild);
			if(p.lChild==null) {
				p.lTag=thread;
				p.lChild=pre;
			}
			if(pre!=null && pre.rChild==null) {  //pre!=null必定要加上
				pre.rTag=thread;
				pre.rChild=p;
			}
			pre=p;                               //別忘了在這個位置加上pre=p
			inThreading(p.rChild);
		}
	}
	
	/*
	 * 中序遍歷二叉線索鏈表表示的二叉樹(按後繼方式)
	 * 書中添加了一個頭結點,本程序中不含頭結點
	 * 思路:先找到最左子結點
	 */
	public void inOrderTraverse() {
		BiThrNode<T> p = root;
		while(p!=null) {
			while(p.lTag==link)
				p=p.lChild;    //找到最左子結點
			System.out.print(p.data);
			while(p.rTag==thread) {   //不是if
				p=p.rChild;
				System.out.print(p.data);
			}
			p=p.rChild;
		}	
		System.out.println();
	}
	
	/*
	 * 中序遍歷方法二(按後繼方式)
	 * 參考別人的博客
	 */
	public void inOrderTraverse2() {
		BiThrNode<T> node = root;
        while(node != null && node.lTag==link) {
            node = node.lChild;
        }
        while(node != null) {
            System.out.print(node.data + ", ");            
            if(node.rTag==thread) {//若是右指針是線索
                node = node.rChild;

            } else {    //若是右指針不是線索,找到右子樹開始的節點
                node = node.rChild;
                while(node != null && node.lTag==link) {
                    node = node.lChild;
                }
            }
        }
        System.out.println();
	}
	
	public static void main(String[] args) {
		BiThrTree<String> aBiThrTree = new BiThrTree<String>();
		aBiThrTree.root=new BiThrNode<String>("A");					//		A
		aBiThrTree.root.lChild=new BiThrNode<String>("B");			//    /   \
		aBiThrTree.root.lChild.lChild=new BiThrNode<String>("C");	    //	 B     D
		aBiThrTree.root.rChild=new BiThrNode<String>("D");			//  /     / \
		aBiThrTree.root.rChild.lChild=new BiThrNode<String>("E");     // C     E   F
		aBiThrTree.root.rChild.rChild=new BiThrNode<String>("F");
		aBiThrTree.inThreading();
		aBiThrTree.inOrderTraverse();
		aBiThrTree.inOrderTraverse2();
	}	
} 

  

CBAEDF
C, B, A, E, D, F, 
BiThrTree

 

推薦閱讀:

  線索二叉樹原理及前序、中序線索化(Java版)(文中對線索二叉樹的介紹和代碼都比較清晰,且更加全面)。

 

 赫夫曼樹及其應用

  帶權路徑長度WPL最小的二叉樹稱爲最優二叉樹,也稱爲赫夫曼樹(Huffman Tree)

 

  赫夫曼編碼:

  推薦閱讀:哈夫曼樹(三)之 Java詳解 

相關文章
相關標籤/搜索