在前一文中,介绍了根据权值进行哈夫曼树的构建(https://blog.youkuaiyun.com/m0_51384638/article/details/116278540)。本文,将对传入的字符串进行编码,得出一个哈夫曼编码表,并根据编码表解码,得到原来的数据。
要实现对字符串进行哈夫曼编码和解码,我认为需要解决的问题如下:
1如何统计频率.每一个字符如何与它的权值建立一一对应的关系。
2.搭建哈夫曼树之后,如何得到每一个字符的哈夫曼编码。
3.根据哈夫曼编码表,如何解码得到原来的字符串。
现在,问题依次来解决
1.将字符串转为字节数组,遍历字节数组,将每个字节出现的频率保存到一个新建的数组中,这个必须得保证两个数组的长度一致。比如说在字节数组中,第一个位置的字节的频率必须对应在第二个数组中的第一个位置。但是我不是特别推荐这种方法,在学过的数据结构中,map就是一个键和值一一对应的关系(不考虑有冲突),使用map存储,在后续的编码和解码可以方便很多。
2.依照左0右1的规则,给哈夫曼中的所有路径进行编码,最终的哈夫曼编码即为从根节点到叶子节点路径的编码拼接得到的字符串。使用上文最后得到的哈夫曼树
3节点对应的哈夫曼编码即为:11000,越靠近根节点的哈夫曼编码越短。
3.从哈夫曼编码得到的字符串的第一位开始,一一与编码表对应,如果出现对应的编码即解码成功。例如:编码表为:{97=10, 98=111, 99=0, 107=110},编码字符串为:1010101111110000110,到了第二位数字就在编码表中找到10对应为97,下一步就是从第三位开始,按照上面的规则进行解码。
代码实现
一、编码
使用到的节点类
、class Node3 implements Comparable<Node3> {
Byte data;//数据域
Node3 left,right;
int weight;//权值域
public Node3(byte data,int weight) {
this.data = data;
this.weight = weight;
}
public Node3(int weight) {
this.weight = weight;
}
public int compareTo(Node3 o) {
// TODO Auto-generated method stub
return this.weight-o.weight;
}
@Override
public String toString() {
return "Node3 [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();
}
}
先统计字符串中每个字符出现的频率,并建立映射关系
/**
*
* @param str 需要统计的字符串
* @return 保存了节点的队列
*/
public static ArrayList<Node3> creatNode(String str) {
byte[] data = str.getBytes();
//array用于保存后续建立起来的节点
ArrayList<Node3> array = new ArrayList