本文根據《大話數據結構》一書,對Java版的二叉樹、線索二叉樹進行了必定程度的實現。html
另:java
二叉排序樹(二叉搜索樹) node
性質1:二叉樹第i層上的結點數目最多爲 2{i-1} (i≥1)。數據結構
性質2:深度爲k的二叉樹至多有2{k}-1個結點(k≥1)。ide
性質3:在任意一棵二叉樹中,若終端結點的個數爲n0,度爲2的結點數爲n2,則n0=n2+1。post
證實提示:分支線總數=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
對一個有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,
推薦閱讀:
線索二叉樹原理及前序、中序線索化(Java版)(文中對線索二叉樹的介紹和代碼都比較清晰,且更加全面)。
帶權路徑長度WPL最小的二叉樹稱爲最優二叉樹,也稱爲赫夫曼樹(Huffman Tree)。
赫夫曼編碼:
推薦閱讀:哈夫曼樹(三)之 Java詳解