java赫夫曼编码(含赫夫曼编码代码)

23 篇文章 2 订阅
2 篇文章 0 订阅

目录

一:赫夫曼编码的介绍

二:赫夫曼编码原理解析

2.1 通信领域中信息的处理方式1——定长编码​

2.2 通信领域中信息的处理方式2——变长编码​

2.3 通信领域中信息的处理方式3——赫夫曼编码

三:赫夫曼编码步骤

四:说明

五:赫夫曼编码代码展示


一:赫夫曼编码的介绍

1 赫夫曼编码也翻译为哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式, 属于一种程序算法。

2 赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。

3 赫夫曼编码广泛地用于数据文件压缩。 其压缩率通常在20%~90%之间。

4 赫夫曼码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,称之为最佳编码。

二:赫夫曼编码原理解析

2.1 通信领域中信息的处理方式1——定长编码

2.2 通信领域中信息的处理方式2——变长编码

2.3 通信领域中信息的处理方式3——赫夫曼编码

三:赫夫曼编码步骤

1 假设要传输的字符串为:i like like like java do you like a java

2 统计各个字符对应的个数:d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5  :9 

3 按照上面字符出现的次数构建一颗赫夫曼树, 次数作为权值。

构建赫夫曼树的步骤如下:

3.1 从小到大进行排序,每个数据都是一个节点,每个节点可以看成是一颗最简单的二叉树。

3.2 取出根节点权值最小的两颗二叉树。

3.3 组成一棵新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和。

3.4 再将这棵新的二叉树,以根节点的权值大小再次排序,不断重复1-2-3-4 的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树。

4 根据赫夫曼树,给各个字符,规定编码 (前缀编码),向左的路径为 0, 向右的路径为 1 ,编码如下:

o:1000 u:10010 d:100110 y:100111 i:101 a:110 k:1110 e:1111 j:0000 v:0001 l:001  :01

5 按照上面的赫夫曼编码,"i like like like java do you like a java" 字符串对应的编码如下:

1010100110111101111010011011110111101001101111011110100001100001110011001111000011001111000100100100110111101111011100100001100001110 

注意:这里使用的是无损压缩。

6 通过赫夫曼编码处理后,长度变为133。

四:说明

1 原来长度是359,压缩了(359-133) / 359 = 62.9%。

2 此编码满足前缀编码, 即字符的编码都不能是其他字符编码的前缀,不会造成匹配的多义性。

3 赫夫曼编码是无损处理方案。

注意
赫夫曼树根据排序方法不同,也可能不太一样,这样对应的赫夫曼编码也不完全一样,但是 wpl 是一样的,都是最小的,最后生成的赫夫曼编码的长度是一样。

比如:如果让每次生成的新的二叉树总是排在权值相同的二叉树的最后一个,则生成的二叉树为下图。

五:赫夫曼编码代码展示

赫夫曼树结点的定义

package tree;

public class HFMCode implements Comparable<HFMCode>{
	private Byte b;
	private int weight;
	
	private HFMCode left;
	private HFMCode right;
	
	public HFMCode(Byte b, int weight) {
		this.b = b;
		this.weight = weight;
	}

	public Byte getB() {
		return b;
	}

	public void setB(Byte b) {
		this.b = b;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	public HFMCode getLeft() {
		return left;
	}

	public void setLeft(HFMCode left) {
		this.left = left;
	}

	public HFMCode getRight() {
		return right;
	}

	public void setRight(HFMCode right) {
		this.right = right;
	}

	@Override
	public String toString() {
		return "HFMCode [b=" + b + ", weight=" + weight + "]";
	}

	@Override
	public int compareTo(HFMCode o) {
		// TODO Auto-generated method stub
		return this.weight - o.weight;
	}
	
	public void preSelect() {
		System.out.println(this);
		if(this.getLeft() != null) {
			this.getLeft().preSelect();
		}
		if(this.getRight() != null) {
			this.getRight().preSelect();
		}
	}
	
	

}

赫夫曼编码

package tree;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class HFMCTree {
	private static Map<Byte,String> map = new HashMap<>();;
	public static void main(String[] args) {
		String str = "Im RenBiaoYu what your name";
		byte[] bytes = str.getBytes();
		HFMCode root = creatTree(counts(bytes));
		Map<Byte,String> m = creatCode(root,"",new StringBuilder());
		System.out.print(Arrays.toString(zip(m, bytes)));
		
	}
	//统计个数
	public static ArrayList<HFMCode> counts(byte[] arr){
		Map<Byte,Integer> map = new HashMap<>();
		for(byte b:arr) {
			Integer i = map.get(b);
			if(i == null) {
				map.put(b, 1);
			}else {
				map.put(b, i + 1);
			}
		}
		//压缩到List集合中方便后序赫夫曼树的建立
		ArrayList<HFMCode> al = new ArrayList<HFMCode>();
		for(Map.Entry<Byte, Integer> entry:map.entrySet()) {
			al.add(new HFMCode(entry.getKey(),entry.getValue()));
		}
		
		return al;
	}
	//创建赫夫曼树
	public static HFMCode creatTree(ArrayList<HFMCode> hfmc) {
		while(hfmc.size() > 1) {
			Collections.sort(hfmc);
			HFMCode left = hfmc.get(0);
			HFMCode right = hfmc.get(1);
			
			HFMCode newCode = new HFMCode(null,left.getWeight() + right.getWeight());
			newCode.setLeft(left);
			newCode.setRight(right);
			
			hfmc.remove(left);
			hfmc.remove(right);
			hfmc.add(newCode);
		}
		return hfmc.get(0);
	}
	//赫夫曼编码
	public static Map<Byte,String> creatCode(HFMCode node, String code, StringBuilder sb){
		StringBuilder stringCode = new StringBuilder(sb);
		stringCode.append(code);
		if(node != null) {
			if(node.getB() == null) {
				creatCode(node.getLeft(),"0",stringCode);
				creatCode(node.getRight(),"1",stringCode);
			}else{
				map.put(node.getB(), stringCode.toString());
				}
		}
		return map;
	}
	//压缩数据
	public static byte[] zip(Map<Byte,String> m,byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for(byte b:bytes) {
			sb.append(m.get(b));
		}
		int length = 0;
		if(sb.length() % 8 == 0) {
			length = sb.length() / 8;
		}else {
			length = sb.length() / 8 + 1;
		}
		//压缩数据的数组
		int index = 0;
		byte[] newbytes = new byte[length];
		for(int i = 0; i < sb.length(); i+=8) {
			String str = "";
			if(i + 8 > sb.length()) {
				str = sb.substring(i);
			}else {
				str = sb.substring(i, i + 8);
			}
			newbytes[index++] = (byte) Integer.parseInt(str, 2);
		}
		return newbytes;
	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值