哈夫曼树及一种java实现

最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。

那么什么是二叉树的带权路径长度呢?

在前面我们介绍过路径和结点的路径长度的概念,而二叉树的路径长度则是指由根结点到所有叶结点的路径长度之和。如果二叉树中的叶结点都具有一定的权值,则可将这一概念加以推广。设二叉树具有n 个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度,记为:

其中Wk 为第k 个叶结点的权值,Lk 为第k 个叶结点的路径长度。如图6.16 所示的二叉树,它的带权路径长度值WPL=2×2+4×2+5×2+3×2=28。

在给定一组具有确定权值的叶结点,可以构造出不同的带权二叉树。例如,给出4 个叶结点,设其权值分别为1,3,5,7,我们可以构造出形状不同的多个二叉树。这些形状不同的二叉树的带权路径长度将各不相同。

这五棵树的带权路径长度分别为:
(a)WPL=1×2+3×2+5×2+7×2=32
(b)WPL=1×3+3×3+5×2+7×1=29
(c)WPL=1×2+3×3+5×3+7×1=33
(d)WPL=7×3+5×3+3×2+1×1=43 

(e)WPL=7×1+5×2+3×3+1×3=29

由此可见,由相同权值的一组叶子结点所构成的二叉树有不同的形态和不同的带权路径长度,那么如何找到带权路径长度最小的二叉树(即哈夫曼树)呢?根据哈夫曼树的定义,一棵二叉树要使其WPL 值最小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。哈夫曼(Haffman)依据这一特点提出了一种方法,这种方法的基本思想是:

(1)由给定的n 个权值{W1,W2,…,Wn}构造n 棵只有一个叶结点的二叉树,从而得到一个二叉树的集合F={T1,T2,…,Tn};

(2)在F 中选取根结点的权值最小和次小的两棵二叉树作为左、右子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为其左、右子树根结点权值之和;

(3)在集合F 中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到集合F 中;

(4)重复(2)(3)两步,当F 中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。

图6.18 给出了前面提到的叶结点权值集合为W={1,3,5,7}的哈夫曼树的构造过程。可以计算出其带权路径长度为29,由此可见,对于同一组给定叶结点所构造的哈夫曼树,树的形状可能不同,但带权路径长度值是相同的,一定是最小的。


下面是参考word2vec的中的代码对上面的{1,3,5,7}实现的哈夫曼树。个人觉得word2vec里面的哈夫曼树实现代码写的特别好:

  

package aturbo.huffman;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;


public class HuffmanTree {
	 public static void make(Collection<? extends HuffmanNode> nodes){

	        TreeSet<HuffmanNode> tree = new TreeSet<HuffmanNode>(nodes);
	        while (tree.size() > 1){
	            HuffmanNode left = tree.pollFirst();
	            HuffmanNode right = tree.pollFirst();
	            HuffmanNode parent = left.merge(right);
	            tree.add(parent);
	        }
	    }
	 
	 public static void main(String[] args){
		 HuffmanNode h1 = new HuffmanNode(1);
		 HuffmanNode h3 = new HuffmanNode(3);
		 HuffmanNode h5 = new HuffmanNode(5);
		 HuffmanNode h7 = new HuffmanNode(7);
		 List<HuffmanNode> nodes = new ArrayList<HuffmanNode>();
		 nodes.add(h1);
		 nodes.add(h3);
		 nodes.add(h5);
		 nodes.add(h7);
		 HuffmanTree.make(nodes);
		 
	 }
}

package aturbo.huffman;


public class HuffmanNode implements Comparable<HuffmanNode>{

	    protected int frequency = 0;
	    protected HuffmanNode parentnode;
	    protected int code = 0;
	    
	    
	    public int getFrequency() {
			return frequency;
		}


		public void setFrequency(int frequency) {
			this.frequency = frequency;
		}


		public HuffmanNode getParentnode() {
			return parentnode;
		}


		public void setParentnode(HuffmanNode parentnode) {
			this.parentnode = parentnode;
		}


		public int getCode() {
			return code;
		}


		public void setCode(int code) {
			this.code = code;
		}


		public HuffmanNode merge(HuffmanNode right){
	        HuffmanNode parent = new HuffmanNode(frequency+right.getFrequency());
	        parentnode = parent;
	        this.code = 0;
	        right.setParentnode(parent);
	        right.setCode(1);
	        return parent;
	    }
		
		public HuffmanNode(int freq){
			frequency = freq;
		}


		@Override
		public int compareTo(HuffmanNode hn) {
			if (frequency > hn.getFrequency()){
	            return 1;
	        } else {
	            return -1;
	        }
		}
	    
}


摘自:http://c.biancheng.net/cpp/html/984.html
参考:word2vec java版:https://github.com/siegfang/word2vec.git

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值