(单纯的代码,霍夫曼编码理论定义请自行查询学习)
定义节点类
实现Comparator接口,重写compare()方法:定义排序标准。
具体代码:
public class Node implements Comparator<Node> {
private String key;
private int weight;
private Node left;
private Node right;
private boolean isLeaf;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public boolean isLeaf() {
return isLeaf;
}
public void setLeaf(boolean leaf) {
isLeaf = leaf;
}
public Node(){}
public Node(String key,int weight){
this.key = key;
this.weight = weight;
this.isLeaf = true;
}
public Node(Node left,Node right,int weight){
this.left = left;
this.right = right;
this.weight = weight;
this.isLeaf = false;
}
@Override
public int compare(Node o1, Node o2) {
return (o1.weight - o2.weight);
}
}
public class Hufuman {
private static final Logger logger = LogManager.getLogger(Hufuman.class);
LinkedList<Node> nodes = new LinkedList<>();
//定义字符权重集合
JSONObject jsonObject = JSONObject.parseObject("{\"A\":60 ,\"B\":45,\"C\":13,\"D\":69,\"E\":14,\"F\":5,\"G\":3}");
private Node tree;
/**
* 根据字符的权重构建树,权重越高,该节点越靠近根节点,编码占位越短
*/
@Before
public void initTree(){
for(Map.Entry<String, Object> node : jsonObject.entrySet()){
nodes.add(new Node(node.getKey(),(int)node.getValue()));
}
while(nodes.size() != 1){
Collections.sort(nodes,new Node());//会根据重写的compare()方法进行排序,由小到大:
Node left = nodes.pop();//按角标顺序依次弹出
Node right = nodes.pop();
Node parent = new Node(left,right,left.getWeight() + right.getWeight());
nodes.add(parent);
}
Node node = nodes.pop();
tree = node;
}
private void encodeMethod(Node root) {
Map<String,String> resultMap = new HashMap<>();
//从根节点开始,左分支为0,右分支为1,由此编码出每个字符的二进制“路径”,放进map
encode(root,"",resultMap);
String str = "ACBDEGF";
String result = "";
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
String key = chars[i]+"";
result += resultMap.get(key);
}
System.out.println(resultMap);
System.out.println(result);
}
private void encode(Node node, String weight, Map<String, String> resultMap) {
if(node.isLeaf()){
resultMap.put(node.getKey(),weight);
return;
}
encode(node.getLeft(),weight + "0",resultMap);
encode(node.getRight(),weight + "1",resultMap);
}
public void decode(){
String result = "";
//{A=10, B=01, C=0011, D=11, E=000, F=00101, G=00100}
//ACBDEGF编码后结果为:10001101110000010000101
String value= "10001101110000010000101";
Node node = null;
Node root = tree;
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
try {
if ('0' == chars[i]) {
node = root.getLeft();
} else if ('1' == chars[i]) {
node = root.getRight();
}
if (node.isLeaf()) {
result += node.getWeight();
root = tree;
} else {
root = node;//此节点不是叶节点,则从此节点开始解析
}
}catch (Exception e){
logger.error("HuoFuMan 解码失败。CHAR= {}, MSG={}",chars, e.getMessage(), e);
}
}
System.out.println(result);//ACBDEGF :解码为:601345691435----》{"A":60 ,"B":45,"C":13,"D":69,"E":14,"F":5,"G":3}
}
@Test
public void test() {
encodeMethod(tree);
decode();
}
}