package com.atguigu.huffmancode;
import com.sun.org.glassfish.external.statistics.CountStatistic;
import com.sun.org.glassfish.external.statistics.StringStatistic;
import java.util.*;
/**
* @创建人 wdl
* @创建时间 2021/3/27
* @描述
*/
public class HuffmanCode {
public static void main(String[] args) {
String content="i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
System.out.println(contentBytes.length);//40
List<Node> nodes = getNodes(contentBytes);
System.out.println(nodes);
//测试一把,创建的二叉树
System.out.println("赫夫曼树");
Node huffmanTreeRoot = createHuffmanTree(nodes);
System.out.println("前序遍历");
huffmanTreeRoot.preOrder();
//测试一把是否生成了对应的赫夫曼编码
getCodes(huffmanTreeRoot,"",stringBuilder);
System.out.println("生成的赫夫曼编码表"+huffmanCodes);
}
//生成赫夫曼树对应的赫夫曼编码
//思路:
//1.将赫夫曼编码表存放在Map<Byte,String>形式
static Map<Byte,String> huffmanCodes= new HashMap<Byte,String>();
// 32->01 97->100...
//2.在生成赫夫曼编码表示,需要去拼接璐姐,定义一个StringBuilder存储某个叶子结点的路径
static StringBuilder stringBuilder=new StringBuilder();
/**
* 功能:将传入的node节点的所有叶子节点的赫夫曼编码的到,并放入到huffmanCodes集合
* @param node 传入节点
* @param code 路径:左子节点是0,右子节点是1
* @param stringBuilder 是用于拼接路径
*/
private static void getCodes(Node node,String code,StringBuilder stringBuilder){
StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);
//将code加入到stringBuild2
stringBuilder2.append(code);
if(node!=null){
//如果node==null不处理
//判断当前node是叶子结点还是非叶子节点
if(node.data==null){//非叶子节点
//递归处理
//向左
getCodes(node.left,"0",stringBuilder2);
//向右
getCodes(node.right,"1",stringBuilder2);
}else {//说明是一个叶子结点
//表示找到了某个叶子节点的最后
huffmanCodes.put(node.data,stringBuilder2.toString());
}
}
}
//前序遍历的方法
private static void preOrder(Node root){
if(root!=null){
root.preOrder();
}else {
System.out.println("赫夫曼树为空");
}
}
/**
*
* @param bytes 接收字节数组
* @return 返回的就是List形式
*/
private static List<Node> getNodes(byte[] bytes){
//1.创建一个ArrayList
ArrayList<Node> nodes = new ArrayList<>();
//遍历bytes 统计每一个byte出现的次数->map[key,value]
HashMap<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> entry:counts.entrySet()){
nodes.add(new Node(entry.getKey(),entry.getValue()));
}
return nodes;
}
//可以通过List创建对应的赫夫曼树
private static Node createHuffmanTree(List<Node> nodes){
while (nodes.size()>1){
//排序,从小到大
Collections.sort(nodes);
//取出第一颗最小的二叉树
Node leftNode = nodes.get(0);
//取出第二颗最小的二叉树
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,它的根节点没有data,只有权值
Node parent=new Node(null,leftNode.weight+rightNode.weight);
parent.left=leftNode;
parent.right=rightNode;
//将已经处理的两颗二叉树从nodes删除
nodes.remove(leftNode);
nodes.remove(rightNode);
//将新的二叉树,加入到nodes
nodes.add(parent);
}
//nodes最后的节点,就是哈夫曼树的根节点
return nodes.get(0);
}
}
//创建Node,待数据和权值
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;
}
@Override
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();
}
}
}
生成赫夫曼编码表
原创
©著作权归作者所有:来自51CTO博客作者Frank___7的原创作品,请联系作者获取转载授权,否则将追究法律责任
上一篇:赫夫曼编码字节数组
下一篇:用赫夫曼树进行文件的压缩
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
赫夫曼编码
定长编码 变长编码 统计不同字符出现的次数 字符所对应的编码 以上的编码在解码时,会存在多义性,所以不是前缀编码 赫夫曼编码 注意点
数据结构与算法 变长编码 赫夫曼编码 -
字符编码表
字符编码表
字符编码表 php 码表 ico -
url编码表
可以支持搜索的url编码,urldecode,ascii。
url编码 asscii码表 ascii