首页 > 代码库 > 哈夫曼树

哈夫曼树

一、     什么是哈夫曼树

是一种带权路径长度最短的二叉树,也称最优二叉树

带权路径长度:WPL=(W1*L1+W2*L2+W3*L3+...+ Wn*Ln)

N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)

 

二、     建立哈夫曼树

已知的一组叶子的权值w1,w2,w3……wn; 
首先把 个叶子结点看做 棵树(仅有一个结点的二叉树),把它们看做一个森林。 
在森林中把权值最小和次小的两棵树合并成一棵树,该树根结点的权值是两棵子树权值之和。这时森林中还有 n-1 棵树。 
重复第步直到森林中只有一棵为止,此树就是哈夫曼树。

现给一组 (n=4) 具体的权值: 2    ,下边是构造具体过程:

 

n 个叶子构成的哈夫曼树其带权路径长度是唯一的,但树形是不唯一的。因为将森林中两棵权值最小和次小的子棵合并时,哪棵做左子树,哪棵做右子树并不严格限制。

 

三、     哈夫曼树的应用


a)       哈夫曼编码

 利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。

其中A,B,C,D对应的哈夫曼编码分别为:111,10,110,0


b)      二路归并排序

假设现在有n个已经排序的文件{d1,d2,….dn},每个文件包含的记录个数对应是{w1,w2,w3…..wn};可以采用两两合并的方法,把所有文件的记录合并到一个大文件中,使得这个文件中的记录全部排序。

              问:采用什么合并次序才能使移动个数最少?

              答:按照哈夫曼树的结构从外部结点到根节点逐层进行合并,一定是一种最佳的合并顺序。

 



四、      哈夫曼树的代码实现

用java实现的哈夫曼树
public class Huffman {
	public static void main(String[] args){
		Huffman huffman = new Huffman();
		int[] a = {2,3,5,7,11,13,17,19,23,29,31,37,41};
		System.out.println(a.length);
		HfTree tree = huffman.createHfTree(a.length , a);
		System.out.println("ht  ww  parent  lchild  rchild ");
		for(int i=0;i<tree.node.length;i++){
			System.out.println(i +" "+ tree.node[i].ww +" "+ tree.node[i].parent +" "+ tree.node[i].lchild +" "+ tree.node[i].rchild);
		}
		
	}
	
	private static int MAXINT=10000;
	public HfTree createHfTree(int m , int a[]){
		HfTree hfTree = new HfTree(m);
		/*初始化哈夫曼树*/
		for(int i=0;i<2*m-1;i++){
			hfTree.node[i].lchild = -1;
			hfTree.node[i].rchild = -1;
			hfTree.node[i].parent = -1;
			if(i<m){
				hfTree.node[i].ww = a[i];
			}
		}
		/*开始生成哈夫曼树*/
		for(int i=0; i<m-1;i++){
			int x1 = 0;
			int x2 = 0;
			int m1 = MAXINT;
			int m2 = MAXINT;
			for(int j=0; j<m+i;j++){
				if(hfTree.node[j].ww < m1 && hfTree.node[j].parent == -1){
					m2 = m1;
					x2 = x1;
					m1 = hfTree.node[j].ww;
					x1 = j;
				}
				else if(hfTree.node[j].ww < m2 && hfTree.node[j].parent == -1){
					m2 = hfTree.node[j].ww;
					x2 = j;
				}
			}
			hfTree.node[x1].parent = m+i;
			hfTree.node[x2].parent = m+i;
			hfTree.node[m+i].ww = m1+m2;
			hfTree.node[m+i].lchild = x1;
			hfTree.node[m+i].rchild = x2;
		}
		hfTree.root = 2*m-2;
		return hfTree;
	}
	
	
	
}


class HfNode{
	public int ww;
	public int parent;
	public int lchild;
	public int rchild;
	
}
 
class HfTree{
	  public HfNode[] node;
	  public int root;
	  public int m;
	 
	 HfTree(int m){
		 this.m = m;
		 this.node = new HfNode[2*m-1];
		//初始化对象数组是必须每个对象都创建
		 for(int i=0;i<2*m-1;i++){
			 node[i] = new HfNode(); 
		 }
	 }
	

		
 }