树结构实际应用(赫夫曼树编码)

基本介绍

  1. 赫夫曼编码也翻译为哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式, 属于一种程序算法
  2. 赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。
  3. 赫夫曼编码广泛地用于数据文件压缩。其压缩率通常在20%~90%之间
  4. 赫夫曼码是可变字长编码(VLC)的一种。Huffman 于1952 年提出一种编码方法,称之为最佳编码

原理剖析

三种处理方式

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

• i like like like java do you like a java // 共40个字符(包括空格)
//对应10进制
• 105 32 108 105 107 101 32 108 105 107 101 32 108 105 107 101 32 106 97 118 97 32 100 111 32 121 111 117 32 108 105 107 101 32 97 32 106 97 118 97
//对应Ascii码
• 01101001 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101010 01100001 01110110 01100001 00100000 01100100 01101111 00100000 01111001 01101111 01110101 00100000 01101100 01101001 01101011 01100101 00100000 01100001 00100000 01101010 01100001 01110110 01100001 //对应的二进制
• 按照二进制来传递信息,总的长度是 359 (包括空格)
• 在线转码 工具 :https://www.mokuge.com/tool/asciito16/

  1. 通信领域中信息的处理方式2-变长编码

• i like like like java do you like a java // 共40个字符(包括空格)
• d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5 :9
// 各个字符对应的个数
• 0= , 1=a, 10=i, 11=e, 100=k, 101=l, 110=o, 111=v, 1000=j, 1001=u, 1010=y, 1011=d
说明:按照各个字符出现的次数进行编码,原则是出现次数越多的,则编码越小,比如 空格出现了9 次, 编码为0 ,其它依次类推.
• 按照上面给各个字符规定的编码,则我们在传输 “i like like like java do you like a java” 数据时,编码就是 10010110100…
• 字符的编码都不能是其他字符编码的前缀,符合此要求的编码叫做前缀编码, 即不能匹配到重复的编码
有二异性,不是前缀编码

  1. 通信领域中信息的处理方式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. 按照上面字符出现的次数构建一颗赫夫曼树, 次数作为权值
    步骤:
    构成赫夫曼树的步骤:
  4. 从小到大进行排序, 将每一个数据,每个数据都是一个节点, 每个节点可以看成是一颗最简单的二叉树
  5. 取出根节点权值最小的两颗二叉树
  6. 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和
  7. 再将这颗新的二叉树,以根节点的权值大小再次排序, 不断重复1-2-3-4 的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树
    在这里插入图片描述
  8. 根据赫夫曼树,给各个字符,规定编码(前缀编码), 向左的路径为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
  9. 按照上面的赫夫曼编码,我们的"i like like like java do you like a java" 字符串对应的编码为(注
    意这里我们使用的无损压缩)
    10101001101111011110100110111101111010011011110111101000011000011100110011110000110
    01111000100100100110111101111011100100001100001110 通过赫夫曼编码处理长度为133
    6) 长度为: 133
    说明:
    原来长度是359 , 压缩了(359-133) / 359 = 62.9%
    此编码满足前缀编码, 即字符的编码都不能是其他字符编码的前缀。不会造成匹配的多义性赫夫曼编码是无损处理方案

注意事项

注意, 这个赫夫曼树根据**排序方法不同,也可能不太一样,这样对应的赫夫曼编码**也不完全一样,但是wpl 是一样的,都是最小的, 最后生成的赫夫曼编码的长度是一样,比如: 如果我们让每次生成的新的二叉树总是排在权值相同的二叉树的最后一个,则生成的二叉树为:
在这里插入图片描述
前缀编码的判断:https://jingyan.baidu.com/article/6079ad0e5db9de69ff86dbed.html

最佳实践-数据压缩

一创建赫夫曼树

  1. 创建节点类
class Node implements Comparable<Node> {
   
	Byte data; // 存放数据(字符)本身,比如'a' => 97 ' ' => 32
	int weight; // 权值, 表示字符出现的次数
	Node left;//
	Node right;

	public Node(Byte data, int weight) {
   

		this.data = data;
		this.weight = weight;
	}

	@Override
	public int compareTo(Node o) {
   
		// 从小到大排序
		return this.weight - o.weight;
	}

	public String toString() {
   
		return "Node [data = " + data + " weight=" + weight + "]";
	}

	// 前序遍历
	public void preOrder() {
   
		System.out.println(this);
		if (this.left != null) {
   
			this.left.preOrder();
		}
		if (this.right != null) {
   
			this.right.preOrder();
		}
	}
}
  1. 创建一个能把字节转换成字节类的方法(返回的就是 List 形式 [Node[date=97 ,weight = 5],)
  2. 创建一个把list转换成赫夫曼树的方法
/**
	 * 
	 * @param bytes 接收字节数组
	 * @return 返回的就是 List 形式 [Node[date=97 ,weight = 5], Node[]date=32,weight =
	 *         9]......],
	 */
	private static List<Node> getNodes(byte[] bytes) {
   

		// 1创建一个ArrayList
		ArrayList<Node> nodes = new ArrayList<Node>();

		// 遍历 bytes , 统计 每一个byte出现的次数->map[key,value]
		Map<Byte, Integer> counts = new HashMap<>();
		for (byte b : bytes) {
   
			Integer count = counts.get(b);
			if (count == null) {
    // Map还没有这个字符数据,第一次
				counts.put(b, 1);
			} else {
   
				counts.put(b, count + 1);
			}
		}

		// 把每一个键值对转成一个Node 对象,并加入到nodes集合
		// 遍历map
		for (Map.Entry<Byte, Integer
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值