笨办法学数据结构 数据压缩——创建字符串对应的赫夫曼树

本介绍

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

原理剖析

Ø 信领域中信息的处 理方式 1- 定长编
i like like like java do you like a java       // 40 个字符 ( 包括空格
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 /
Ø 信领域中信息的处 理方式 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" 数据时,编码就是
10 0 101 10 100 ... 
字符的编码都不能是其他字符编码的前缀,符合此要求的编码叫做前缀编 码, 即不能匹配到重复的编码 ( 这个在 赫夫 曼编码 中,我们还要进行举例说明 , 不捉急 )

//根据赫夫曼树,给各个字符

//规定编码 , 向左的路径为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

照上面的赫夫曼编码,我们的"i like like like java do you like a java"   字符串对应的编码为 (意这里我们使用的无损压缩)

1010100110111101111010011011110111101001101111011110100001100001110011001111000011001111000100100100110111101111011100100001100001110

长度为 : 133

:

1) 原来长度是  359 , 压缩了  (359-133) / 359 = 62.9%
2) 此编码满足前缀编码 , 即字 符的编码都不能是其他字符编码的前 缀。 会造成匹配的多义性

, 这个赫夫曼树根据排序方法不同,也可能不太一样这样对应的赫夫曼编码也不完全一样,但wpl 是一样的,都是最小的, 比如: 如果我们让每次生成的新的二叉树总是排在权值相同的二叉树的最后一个,则生成的二叉树为:

代码详解:

package com.liu.huffmancode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Huffmancode {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String content = "i like like like java do you like a java";
		byte[] contentBytes = content.getBytes();
		List<Node> nodes = getNodes(contentBytes);
		System.out.println("nodes=" + nodes);
		System.out.println("赫夫曼树");
		Node huffmanTreeRoot = creatHuffManCode(nodes);
		System.out.println("前序遍历");
		huffmanTreeRoot.preOrder();
	}

	public static void preOrder(Node root) {
		if (root != null) {
			root.preOrder();
		} else {
			System.out.println("赫夫曼树为空");
		}
	}

	public static List<Node> getNodes(byte arry[]) {
		List<Node> nodes = new ArrayList<Node>();

		Map<Byte, Integer> counts = new HashMap<>();
		for (byte b : arry) {
			Integer count = counts.get(b);
			if (count == null) {
				counts.put(b, 1);
			} else {
				counts.put(b, count+1);
			}
		}
		for(Map.Entry<Byte, Integer> entry: counts.entrySet()) {
			nodes.add(new Node(entry.getKey(), entry.getValue()));
		}
		return nodes;
	}

	public static Node creatHuffManCode(List<Node> nodes) {

		while (nodes.size() > 1) {
			Collections.sort(nodes);

			Node leftnode = nodes.get(0);
			Node rightnode = nodes.get(1);

			Node patten = new Node(null, leftnode.value + rightnode.value);
			patten.left = leftnode;
			patten.right = rightnode;

			nodes.remove(leftnode);
			nodes.remove(rightnode);
			nodes.add(patten);
		}

		return nodes.get(0);
	}
}

class Node implements Comparable<Node> {
	Byte data;
	int value;
	Node left;
	Node right;

	public Node(Byte data, int value) {
		this.data = data;
		this.value = value;
	}


	@Override
	public int compareTo(Node o) {
		// TODO Auto-generated method stub
		return this.value - o.value;
	}

	@Override
	public String toString() {
		return "Node [data=" + data + ", value=" + value + "]";
	}

	public void preOrder() {
		System.out.println(this);
		if (this.left != null) {
			this.left.preOrder();
			;
		}
		if (this.right != null) {
			this.right.preOrder();
			;
		}
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只猪的思考

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值