Java数据结构和算法:哈夫曼树
本章介紹哈夫曼樹。和以往一樣,本文會先對哈夫曼樹的理論知識進行簡單介紹,然后給出C語言的實現。后續再分別給出C++和Java版本的實現;實現的語言雖不同,但是原理如出一轍,選擇其中之一進行了解即可。若文章有錯誤或不足的地方,請幫忙指出!
哈夫曼樹的介紹
在一棵二叉樹中由根結點到某個結點所經過的分支序列叫做由根結點到這個結點的路徑,由根結點到某個結點所經過的分支數稱為由根結點到該結點的路徑長度。由根結點到所有葉結點的路徑長度之和稱為該二叉樹的路徑長度。
如果二叉樹中每一個葉結點都帶有某一確定值,就可以將二叉樹的路徑長度的概念加以推廣。設一棵具有n個帶權值葉結點的二叉樹,那么從根結點到各個葉結點的路徑長度與對應葉結點權值的乘積之和叫做二叉樹的帶權路徑長度,記作:
其中Wk為第k個葉結點的權值,Lk為第K個葉結點的路徑長度。
如果給定一組具體確定權值的葉結點,可以構造出葉結點數相同的形態各異的二叉樹。例如,給定4個葉子結點,其權值分別為(3、5、9、12)。可以構造出多棵形狀不同的二叉樹,它們的帶權路徑長度不一定相同。圖6-21給出了其中三棵不同形狀的二叉樹。它們的帶權路徑長度為分別為58、54和76。
由此可見,對于一組確定權值的葉結點,所構造出的不同形態二叉樹的帶權路徑長度并不相同。在此把其中具有最小帶權路徑長度的二叉樹稱為最優二叉樹,最優二叉樹也稱作哈夫曼樹,可以證明,圖(c)所示的二叉樹就是一棵哈夫曼樹。
根據哈夫曼樹的定義,要使一棵二叉樹的其WPL值最小,顯然必須使權值越大的葉結點越靠近根結點,而權值越小的結點越遠離根結點。
Huffman Tree,中文名是哈夫曼樹或霍夫曼樹,它是最優二叉樹。
定義:給定n個權值作為n個葉子結點,構造一棵二叉樹,若樹的帶權路徑長度達到最小,則這棵樹被稱為哈夫曼樹。 這個定義里面涉及到了幾個陌生的概念,下面就是一顆哈夫曼樹,我們來看圖解答。
路徑和路徑長度
定義:在一棵樹中,從一個結點往下可以達到的孩子或孫子結點之間的通路,稱為路徑。通路中分支的數目稱為路徑長度。若規定根結點的層數為1,則從根結點到第L層結點的路徑長度為L-1。 
 例子:100和80的路徑長度是1,50和30的路徑長度是2,20和10的路徑長度是3。
結點的權及帶權路徑長度
定義:若將樹中結點賦給一個有著某種含義的數值,則這個數值稱為該結點的權。結點的帶權路徑長度為:從根結點到該結點之間的路徑長度與該結點的權的乘積。 
 例子:節點20的路徑長度是3,它的帶權路徑長度= 路徑長度 * 權 = 3 * 20 = 60。
樹的帶權路徑長度
定義:樹的帶權路徑長度規定為所有葉子結點的帶權路徑長度之和,記為WPL。 
 例子:示例中,樹的WPL= 1*100 + 2*80 + 3*20 + 3*10 = 100 + 160 + 60 + 30 = 350。
比較下面兩棵樹
上面的兩棵樹都是以{10, 20, 50, 100}為葉子節點的樹。
左邊的樹WPL=2*10 + 2*20 + 2*50 + 2*100 = 360 
 右邊的樹WPL=350
左邊的樹WPL > 右邊的樹的WPL。你也可以計算除上面兩種示例之外的情況,但實際上右邊的樹就是{10,20,50,100}對應的哈夫曼樹。至此,應該堆哈夫曼樹的概念有了一定的了解了,下面看看如何去構造一棵哈夫曼樹。
哈夫曼樹的圖文解析
假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設為 w1、w2、…、wn,哈夫曼樹的構造規則為:
以{5,6,7,8,15}為例,來構造一棵哈夫曼樹。
第1步:創建森林,森林包括5棵樹,這5棵樹的權值分別是5,6,7,8,15。
第2步:在森林中,選擇根節點權值最小的兩棵樹(5和6)來進行合并,將它們作為一顆新樹的左右孩子(誰左誰右無關緊要,這里,我們選擇較小的作為左孩子),并且新樹的權值是左右孩子的權值之和。即,新樹的權值是11。 然后,將”樹5”和”樹6”從森林中刪除,并將新的樹(樹11)添加到森林中。
第3步:在森林中,選擇根節點權值最小的兩棵樹(7和8)來進行合并。得到的新樹的權值是15。 然后,將”樹7”和”樹8”從森林中刪除,并將新的樹(樹15)添加到森林中。
第4步:在森林中,選擇根節點權值最小的兩棵樹(11和15)來進行合并。得到的新樹的權值是26。 然后,將”樹11”和”樹15”從森林中刪除,并將新的樹(樹26)添加到森林中。
第5步:在森林中,選擇根節點權值最小的兩棵樹(15和26)來進行合并。得到的新樹的權值是41。 然后,將”樹15”和”樹26”從森林中刪除,并將新的樹(樹41)添加到森林中。
此時,森林中只有一棵樹(樹41)。這棵樹就是我們需要的哈夫曼樹!
哈夫曼樹的基本操作
哈夫曼樹的重點是如何構造哈夫曼樹。本文構造哈夫曼時,用到了以前介紹過的”(二叉堆)最小堆”。下面對哈夫曼樹進行講解。
1. 基本定義
typedef int Type;typedef struct _HuffmanNode {Type key; // 權值struct _HuffmanNode *left; // 左孩子struct _HuffmanNode *right; // 右孩子struct _HuffmanNode *parent; // 父節點 } HuffmanNode, *HuffmanTree;HuffmanNode是哈夫曼樹的節點類。
2. 構造哈夫曼樹
/** 創建Huffman樹** 參數說明:* a 權值數組* size 數組大小** 返回值:* Huffman樹的根*/ HuffmanNode* create_huffman(Type a[], int size) {int i;HuffmanNode *left, *right, *parent;// 建立數組a對應的最小堆create_minheap(a, size);for(i=0; i<size-1; i++){ left = dump_from_minheap(); // 最小節點是左孩子right = dump_from_minheap(); // 其次才是右孩子// 新建parent節點,左右孩子分別是left/right;// parent的大小是左右孩子之和parent = huffman_create_node(left->key+right->key, left, right, NULL);left->parent = parent;right->parent = parent;// 將parent節點數據拷貝到"最小堆"中if (dump_to_minheap(parent)!=0){printf("插入失敗!\n結束程序\n");destroy_huffman(parent);parent = NULL;break;}} // 銷毀最小堆destroy_minheap();return parent; }首先通過create_huffman(a, size)來一個最小堆。最小堆構造完成之后,進入for循環。
每次循環時:
(01) 首先,將最小堆中的最小節點拷貝一份并賦值給left,然后重塑最小堆(將最小節點和后面的節點交換位置,接著將”交換位置后的最小節點”之前的全部元素重新構造成最小堆);
(02) 接著,再將最小堆中的最小節點拷貝一份并將其賦值right,然后再次重塑最小堆;
(03) 然后,新建節點parent,并將它作為left和right的父節點;
(04) 接著,將parent的數據復制給最小堆中的指定節點。
在二叉堆中已經介紹過堆,這里就不再對堆的代碼進行說明了。若有疑問,直接參考后文的源碼。其它的相關代碼,也Please RTFSC(Read The Fucking Source Code)!
哈夫曼樹在編碼問題中的應用
在數據通信中,經常需要將傳送的電文轉換成由二進制數字0、1組成的串,一般稱之為編碼。例如,假設要傳送的電文為AADDBCAAABDDCADAAADD,電文中只有A、B、C、D四種字符;若這四種字符的編碼分別為:A(00)、B(01)、C(10)、D(11),則電文的代碼為:0000111101100000000111111000110000001111,電文代碼的長度為40。在這種編碼方案中,四種字符的編碼長度均為2,這是一種等長編碼。
在傳送電文時,人們總是希望傳送時間盡可能短,這就要求使電文代碼長度盡可能短。顯然,上述編碼方案所產生的電文代碼還不夠短。如果這四種字符的編碼分別為:A(0)、B(1)、C(10)、D(01),則用此編碼方案對上述電文進行編碼得到的電文代碼為:00010111000010101100010000101,此電文代碼的長度只有29。但這樣的電文代碼是無法正確翻譯成原來的電文的。顯然對“01”,你可以認為是“D”,也可以認為是“AB”。因為這四個字符的編碼不是前綴碼(前綴碼要求任一字符的編碼均非其他字符編碼的前綴),因而無法獲得唯一的譯碼。
可以利用哈夫曼樹構造出使電文代碼總長最短的編碼方案。具體做法如下:設需要編碼的字符集合為{C1、C2、…、Cn},它們在電文中出現的次數或頻率集合為{W1、W2、…、Wn}。以C1、C2、…、Cn作為葉結點,W1、W2、…、Wn作為它們的權值,構造一棵哈夫曼樹,規定哈夫曼樹中的左分支代表0,右分支代表1,則從根結點到每個葉結點所經過的路徑分支組成的0或1序列作為該葉結點對應字符的編碼,我們稱之為哈夫曼編碼。
例如:對于一段電文:AADDBCAAABDDCADAAADDCDDBAACCA。其字符集合為:{A、B、C、D},各個字符出現的頻率(次數)是 W={12、3、5、9}。若給每個字符以等長編碼:A(00)、B(10)、C(01)、D(11)。則電文代碼的長度為:(12+3+5+9)*2=58。
若按各個字符出現的頻率不同而給予不等長編碼,可望減少電文代碼的長度。因各字符出現的頻率為{12/29、3/29、5/29、9/29},化成整數為{12、3、5、9},以它們為各葉結點上的權值,建立哈夫曼樹,如圖6-23所示,得哈夫曼編碼為:A(0)、B(100)、C(101)、D(11)。它的總代碼長度:12*1+(3+5)*2+9*3=54,正好等于哈夫曼樹的帶權路徑長度WPL,顯然比等長編碼的代碼長度要短。哈夫曼編碼是一種前綴編碼,解碼時不會混淆。
定長編碼、不定長編碼,前綴編碼、非前綴編碼,左0右1,帶權編碼
1. 哈夫曼樹的介紹
Huffman Tree,中文名是哈夫曼樹或霍夫曼樹,它是最優二叉樹。
定義:給定n個權值作為n個葉子結點,構造一棵二叉樹,若樹的帶權路徑長度達到最小,則這棵樹被稱為哈夫曼樹。 這個定義里面涉及到了幾個陌生的概念,下面就是一顆哈夫曼樹,我們來看圖解答。
1.1 路徑和路徑長度
定義:在一棵樹中,從一個結點往下可以達到的孩子或孫子結點之間的通路,稱為路徑。通路中分支的數目稱為路徑長度。若規定根結點的層數為1,則從根結點到第L層結點的路徑長度為L-1。
例子:100和80的路徑長度是1,50和30的路徑長度是2,20和10的路徑長度是3。
1.2 結點的權及帶權路徑長度
定義:若將樹中結點賦給一個有著某種含義的數值,則這個數值稱為該結點的權。結點的帶權路徑長度為:從根結點到該結點之間的路徑長度與該結點的權的乘積。
例子:節點20的路徑長度是3,它的帶權路徑長度= 路徑長度 * 權 = 3 * 20 = 60。
1.3 樹的帶權路徑長度
定義:樹的帶權路徑長度規定為所有葉子結點的帶權路徑長度之和,記為WPL。
例子:示例中,樹的WPL= 1**100 + 2**80 + 3**20 + 3**10 = 100 + 160 + 60 + 30 = 350。
比較下面兩棵樹
上面的兩棵樹都是以{10, 20, 50, 100}為葉子節點的樹。
左邊的樹WPL=2*10 + 2*20 + 2*50 + 2*100 = 360
右邊的樹WPL=350
左邊的樹WPL > 右邊的樹的WPL。你也可以計算除上面兩種示例之外的情況,但實際上右邊的樹就是{10,20,50,100}對應的哈夫曼樹。至此,應該堆哈夫曼樹的概念有了一定的了解了,下面看看如何去構造一棵哈夫曼樹。
2. 哈夫曼樹的圖文解析
假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設為 w1、w2、…、wn,哈夫曼樹的構造規則為:
1. 將w1、w2、…,wn看成是有n 棵樹的森林(每棵樹僅有一個結點); 
 2. 在森林中選出根結點的權值最小的兩棵樹進行合并,作為一棵新樹的左、右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和; 
 3. 從森林中刪除選取的兩棵樹,并將新樹加入森林; 
 4. 重復(02)、(03)步,直到森林中只剩一棵樹為止,該樹即為所求得的哈夫曼樹。
以{5,6,7,8,15}為例,來構造一棵哈夫曼樹。
第1步:創建森林,森林包括5棵樹,這5棵樹的權值分別是5,6,7,8,15。 
 第2步:在森林中,選擇根節點權值最小的兩棵樹(5和6)來進行合并,將它們作為一顆新樹的左右孩子(誰左誰右無關緊要,這里,我們選擇較小的作為左孩子),并且新樹的權值是左右孩子的權值之和。即,新樹的權值是11。 然后,將”樹5”和”樹6”從森林中刪除,并將新的樹(樹11)添加到森林中。 
 第3步:在森林中,選擇根節點權值最小的兩棵樹(7和8)來進行合并。得到的新樹的權值是15。 然后,將”樹7”和”樹8”從森林中刪除,并將新的樹(樹15)添加到森林中。 
 第4步:在森林中,選擇根節點權值最小的兩棵樹(11和15)來進行合并。得到的新樹的權值是26。 然后,將”樹11”和”樹15”從森林中刪除,并將新的樹(樹26)添加到森林中。 
 第5步:在森林中,選擇根節點權值最小的兩棵樹(15和26)來進行合并。得到的新樹的權值是41。 然后,將”樹15”和”樹26”從森林中刪除,并將新的樹(樹41)添加到森林中。 
 此時,森林中只有一棵樹(樹41)。這棵樹就是我們需要的哈夫曼樹!
3. 哈夫曼樹的基本操作
哈夫曼樹的重點是如何構造哈夫曼樹。本文構造哈夫曼時,用到了以前介紹過的”(二叉堆)最小堆”。下面對哈夫曼樹進行講解。
基本定義
public class HuffmanNode implements Comparable, Cloneable {protected int key; // 權值protected HuffmanNode left; // 左孩子protected HuffmanNode right; // 右孩子protected HuffmanNode parent; // 父結點protected HuffmanNode(int key, HuffmanNode left, HuffmanNode right, HuffmanNode parent) {this.key = key;this.left = left;this.right = right;this.parent = parent;}@Overridepublic Object clone() {Object obj=null;try {obj = (HuffmanNode)super.clone();//Object 中的clone()識別出你要復制的是哪一個對象。 } catch(CloneNotSupportedException e) {System.out.println(e.toString());}return obj; }@Overridepublic int compareTo(Object obj) {return this.key - ((HuffmanNode)obj).key;} }HuffmanNode是哈夫曼樹的節點類。
public class Huffman {private HuffmanNode mRoot; // 根結點... }Huffman是哈夫曼樹對應的類,它包含了哈夫曼樹的根節點和哈夫曼樹的相關操作。
4. 構造哈夫曼樹
/* * 創建Huffman樹** @param 權值數組*/ public Huffman(int a[]) {HuffmanNode parent = null;MinHeap heap;// 建立數組a對應的最小堆heap = new MinHeap(a);for(int i=0; i<a.length-1; i++) { HuffmanNode left = heap.dumpFromMinimum(); // 最小節點是左孩子HuffmanNode right = heap.dumpFromMinimum(); // 其次才是右孩子// 新建parent節點,左右孩子分別是left/right;// parent的大小是左右孩子之和parent = new HuffmanNode(left.key+right.key, left, right, null);left.parent = parent;right.parent = parent;// 將parent節點數據拷貝到"最小堆"中heap.insert(parent);}mRoot = parent;// 銷毀最小堆heap.destroy(); }首先創建最小堆,然后進入for循環。每次循環時:
- 首先,將最小堆中的最小節點拷貝一份并賦值給left,然后重塑最小堆(將最小節點和后面的節點交換位置,接著將”交換位置后的最小節點”之前的全部元素重新構造成最小堆);
- 接著,再將最小堆中的最小節點拷貝一份并將其賦值right,然后再次重塑最小堆;
- 然后,新建節點parent,并將它作為left和right的父節點;
- 接著,將parent的數據復制給最小堆中的指定節點。
在二叉堆中已經介紹過堆,這里就不再對堆的代碼進行說明了。若有疑問,直接參考后文的源碼。其它的相關代碼,也Please RTFSC(Read The Fucking Source Code)!
5. 哈夫曼樹的完整源碼
哈夫曼樹的節點類(HuffmanNode.java)
/*** Huffman節點類(Huffman.java的輔助類)** @author skywang* @date 2014/03/27*/public class HuffmanNode implements Comparable, Cloneable {protected int key; // 權值protected HuffmanNode left; // 左孩子protected HuffmanNode right; // 右孩子protected HuffmanNode parent; // 父結點protected HuffmanNode(int key, HuffmanNode left, HuffmanNode right, HuffmanNode parent) {this.key = key;this.left = left;this.right = right;this.parent = parent;}@Overridepublic Object clone() {Object obj=null;try {obj = (HuffmanNode)super.clone();//Object 中的clone()識別出你要復制的是哪一個對象。 } catch(CloneNotSupportedException e) {System.out.println(e.toString());}return obj; }@Overridepublic int compareTo(Object obj) {return this.key - ((HuffmanNode)obj).key;} }哈夫曼樹的實現文件(Huffman.java)
/*** Huffman樹** @author skywang* @date 2014/03/27*/import java.util.List; import java.util.ArrayList; import java.util.Collections;public class Huffman {private HuffmanNode mRoot; // 根結點/* * 創建Huffman樹** @param 權值數組*/public Huffman(int a[]) {HuffmanNode parent = null;MinHeap heap;// 建立數組a對應的最小堆heap = new MinHeap(a);for(int i=0; i<a.length-1; i++) { HuffmanNode left = heap.dumpFromMinimum(); // 最小節點是左孩子HuffmanNode right = heap.dumpFromMinimum(); // 其次才是右孩子// 新建parent節點,左右孩子分別是left/right;// parent的大小是左右孩子之和parent = new HuffmanNode(left.key+right.key, left, right, null);left.parent = parent;right.parent = parent;// 將parent節點數據拷貝到"最小堆"中heap.insert(parent);}mRoot = parent;// 銷毀最小堆heap.destroy();}/** 前序遍歷"Huffman樹"*/private void preOrder(HuffmanNode tree) {if(tree != null) {System.out.print(tree.key+" ");preOrder(tree.left);preOrder(tree.right);}}public void preOrder() {preOrder(mRoot);}/** 中序遍歷"Huffman樹"*/private void inOrder(HuffmanNode tree) {if(tree != null) {inOrder(tree.left);System.out.print(tree.key+" ");inOrder(tree.right);}}public void inOrder() {inOrder(mRoot);}/** 后序遍歷"Huffman樹"*/private void postOrder(HuffmanNode tree) {if(tree != null){postOrder(tree.left);postOrder(tree.right);System.out.print(tree.key+" ");}}public void postOrder() {postOrder(mRoot);}/** 銷毀Huffman樹*/private void destroy(HuffmanNode tree) {if (tree==null)return ;if (tree.left != null)destroy(tree.left);if (tree.right != null)destroy(tree.right);tree=null;}public void destroy() {destroy(mRoot);mRoot = null;}/** 打印"Huffman樹"** key -- 節點的鍵值 * direction -- 0,表示該節點是根節點;* -1,表示該節點是它的父結點的左孩子;* 1,表示該節點是它的父結點的右孩子。*/private void print(HuffmanNode tree, int key, int direction) {if(tree != null) {if(direction==0) // tree是根節點System.out.printf("%2d is root\n", tree.key);else // tree是分支節點System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");print(tree.left, tree.key, -1);print(tree.right,tree.key, 1);}}public void print() {if (mRoot != null)print(mRoot, mRoot.key, 0);} }哈夫曼樹對應的最小堆(MinHeap.java)
/*** 最小堆(Huffman.java的輔助類)** @author skywang* @date 2014/03/27*/import java.util.ArrayList; import java.util.List;public class MinHeap {private List<HuffmanNode> mHeap; // 存放堆的數組/* * 創建最小堆** 參數說明:* a -- 數據所在的數組*/protected MinHeap(int a[]) {mHeap = new ArrayList<HuffmanNode>();// 初始化數組for(int i=0; i<a.length; i++) {HuffmanNode node = new HuffmanNode(a[i], null, null, null);mHeap.add(node);}// 從(size/2-1) --> 0逐次遍歷。遍歷之后,得到的數組實際上是一個最小堆。for (int i = a.length / 2 - 1; i >= 0; i--)filterdown(i, a.length-1);}/* * 最小堆的向下調整算法** 注:數組實現的堆中,第N個節點的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 參數說明:* start -- 被下調節點的起始位置(一般為0,表示從第1個開始)* end -- 截至范圍(一般為數組中最后一個元素的索引)*/protected void filterdown(int start, int end) {int c = start; // 當前(current)節點的位置int l = 2*c + 1; // 左(left)孩子的位置HuffmanNode tmp = mHeap.get(c); // 當前(current)節點while(l <= end) {// "l"是左孩子,"l+1"是右孩子if(l < end && (mHeap.get(l).compareTo(mHeap.get(l+1))>0))l++; // 左右兩孩子中選擇較小者,即mHeap[l+1]int cmp = tmp.compareTo(mHeap.get(l));if(cmp <= 0)break; //調整結束else {mHeap.set(c, mHeap.get(l));c = l;l = 2*l + 1; } } mHeap.set(c, tmp);}/** 最小堆的向上調整算法(從start開始向上直到0,調整堆)** 注:數組實現的堆中,第N個節點的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 參數說明:* start -- 被上調節點的起始位置(一般為數組中最后一個元素的索引)*/protected void filterup(int start) {int c = start; // 當前節點(current)的位置int p = (c-1)/2; // 父(parent)結點的位置 HuffmanNode tmp = mHeap.get(c); // 當前(current)節點while(c > 0) {int cmp = mHeap.get(p).compareTo(tmp);if(cmp <= 0)break;else {mHeap.set(c, mHeap.get(p));c = p;p = (p-1)/2; } }mHeap.set(c, tmp);} /* * 將node插入到二叉堆中*/protected void insert(HuffmanNode node) {int size = mHeap.size();mHeap.add(node); // 將"數組"插在表尾filterup(size); // 向上調整堆}/** 交換兩個HuffmanNode節點的全部數據*/private void swapNode(int i, int j) {HuffmanNode tmp = mHeap.get(i);mHeap.set(i, mHeap.get(j));mHeap.set(j, tmp);}/* * 新建一個節點,并將最小堆中最小節點的數據復制給該節點。* 然后除最小節點之外的數據重新構造成最小堆。** 返回值:* 失敗返回null。*/protected HuffmanNode dumpFromMinimum() {int size = mHeap.size();// 如果"堆"已空,則返回if(size == 0)return null;// 將"最小節點"克隆一份,將克隆得到的對象賦值給nodeHuffmanNode node = (HuffmanNode)mHeap.get(0).clone();// 交換"最小節點"和"最后一個節點"mHeap.set(0, mHeap.get(size-1));// 刪除最后的元素mHeap.remove(size-1);if (mHeap.size() > 1)filterdown(0, mHeap.size()-1);return node;}// 銷毀最小堆protected void destroy() {mHeap.clear();mHeap = null;} }哈夫曼樹的測試程序(HuffmanTest.java)
/*** Huffman樹的測試程序** @author skywang* @date 2014/03/27*/public class HuffmanTest {private static final int a[]= {5,6,8,7,15};public static void main(String[] args) {int i;Huffman tree;System.out.print("== 添加數組: ");for(i=0; i<a.length; i++) System.out.print(a[i]+" ");// 創建數組a對應的Huffman樹tree = new Huffman(a);System.out.print("\n== 前序遍歷: ");tree.preOrder();System.out.print("\n== 中序遍歷: ");tree.inOrder();System.out.print("\n== 后序遍歷: ");tree.postOrder();System.out.println();System.out.println("== 樹的詳細信息: ");tree.print();// 銷毀二叉樹tree.destroy();} }總結
以上是生活随笔為你收集整理的Java数据结构和算法:哈夫曼树的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Java数据结构与算法:红黑树
- 下一篇: Java数据结构和算法:图
