Java数据结构之哈夫曼树

背景

由于目前常用的图像、音频等多媒体的信息量巨大,因此必须采用数据压缩技术来存储和传输。数据压缩技术通过对数据进行重新编码来压缩存储,以便减少数据占用的存储空间,在使用时再进行解压缩,恢复数据的原有特性。
压缩方法主要由有损压缩和无损压缩。有损压缩是指压缩过程中可能会丢失数据信息;无损压缩是指压缩存储数据的全部信息,保证解压后的数据不丢失。哈夫曼编码是一种无损压缩技术。

基本概念

  1. 结点间路径:从一个结点到另一个结点所经过的结点序列
  2. 结点路径长度:从根结点到结点的路径上的边数
  3. 结点的权值:人为赋予结点的一个具有某种实际意义的值(例:可以为某个数出现的频数等)
  4. 结点的带权路径长度:结点的权值和结点的路径长度的乘积
  5. 树的带权路径长度:树的叶节点的带权路径长度之和(WPL)
  6. 最优二叉树:指n个带有权值的叶子结点作为二叉树, 构造出的具有最小带权路径长度的二叉树,即哈弗曼树

特点

  1. 权值大的,路径短,权值小的,路径大;
  2. 只有度为0(叶子结点)和度为2(分支结点)的结点,不存在度为1的结点

核心思想

由给定的n个结点作为根结点构成森林,依次选取其中权值最小的两个根结点作为左右子结点,并向上合并构成其父节点。将该父节点加入森林,并同时删除已选中的两个子结点。重复抽取,直到森林中只有一颗树为止。

  1. 初始化:由给定n个具有确定权值的树构成森林,森林中的每个树只有根结点,即{w1,w2,w3,…,wn},其中wi为权值
  2. 选取与合并:从森林中选取权值最小的两个树,分别作为左右子树从而构成一个新的树,新树的根结点权值为这两个左右子树的权值之和
  3. 添加与删除:从森林中删除选出的两个树,同时加入新生成的树
  4. 重复:继续循环(2)(3)步骤,知道只剩一个树为止,即为哈弗曼树

存储结构

  1. 设置长度为2n-1的数组(n为森林中根结点个数,最多具有2n-1个结点)
  2. 以链表结构构造哈夫曼结点

实现代码

public class HuffmanTree {
	private class HuffmanNode{
		public int weight;//哈夫曼结点的权重
		public boolean flag;//标记是否已经进入哈弗曼树
		public HuffmanNode lchild,rchild,parent;//保存当前节点的左右孩子结点及双亲结点
		
		HuffmanNode(){
			this(0);
		}
		
		HuffmanNode(int weight){
			this.weight = weight;
			flag = false;
			lchild = rchild = parent = null;
		}
		
	}
	
	/**
	 * 根据根结点权值数组构建哈夫曼树
	 * @param w	所有结点的权值构成的数组
	 */
	public HuffmanTree(int[] w) {
		int l = w.length;
		int n = 2 * l - 1;// 哈夫曼结点数
		HuffmanNode[] node = new HuffmanNode[n];
		for(int i=0;i<n;i++) 
			node[i] = new HuffmanNode(w[i]);//初始化森林
		for(int i=l;i<n;i++) {
			HuffmanNode m1 = selectMin(node,i);
			m1.flag = true;
			HuffmanNode m2 = selectMin(node,i);
			m2.flag = true;
			node[i].lchild = m1;
			node[i].rchild = m2;
			node[i].weight = m1.weight + m2.weight;
			m1.parent = node[i];
			m2.parent = node[i];
		}
	}
	/**
	 * 从哈夫曼结点数组中选取权值最小的结点
	 * @param node 保存哈夫曼结点的数组
	 * @param len 数组的长度
	 * @return
	 */
	private HuffmanNode selectMin(HuffmanNode[] node, int len) {
		int min = 0;
		for(int i=1;i<len;i++) {
			if(!node[i].flag&&(node[i].weight<node[min].weight))
				min = i;
		}
		return node[min];
	}
	
	/**
	 * 构建哈夫曼编码
	 * @param node 哈夫曼结点数组
	 * @param n 数组长度
	 * @return
	 */
	public int[][] HuffmanCode(HuffmanNode[] node, int n){
		int[][] HuffmanCode = new int[n][n];
		for(int i=0;i<n;i++) {
			int k = n-1;
			HuffmanNode t = node[i],p = t.parent;
			for(;p!=null;p=p.parent) {
				if(p.lchild == t)
					HuffmanCode[i][k--] = 0;
				else
					HuffmanCode[i][k--] = 1;
			}
		}
		
		return HuffmanCode;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值