package com.coderman.datastruct.tree;
import org.junit.Test;
import java.util.*;
public class HuffmanCodingTest {
private static String data="i like like like java do you like a java";
public static void main(String[] args) {
HTree hTree = new HTree(data);
System.out.println("要传输的字符串");
System.out.println(data);
System.out.println("生成编码表");
System.out.println(hTree.huffmanCodeTable);
System.out.println("编码后的数据:【反码---> 每8位一个字节】");
System.out.println(hTree.code());
System.out.println("编码后的字节数组");
System.out.println(Arrays.toString(hTree.zip()));
}
@Test
public void test(){
String name="zhangyukang is a cool boy~";
HTree hTree = new HTree(name);
byte[] data = hTree.getData();
System.out.println(Arrays.toString(data));
}
}
class HTree{
private String value;
private TNode root;
private byte[] data;
public Map<Character,String> huffmanCodeTable=new HashMap<>();
private StringBuilder stringBuilder=new StringBuilder();
public TNode getRoot() {
return root;
}
public byte[] getData() {
return data;
}
public void setRoot(TNode root) {
this.root = root;
}
public HTree(String value){
this.value=value;
this.root=createTree(value);
createHuffmanTable(this.root);
this.data=zip();
}
public void createHuffmanTable(TNode root){
createHuffmanTable(root,"",this.stringBuilder);
}
public void createHuffmanTable(TNode current,String code,StringBuilder stringBuilder){
StringBuilder stringBuilder1=new StringBuilder(stringBuilder);
stringBuilder1.append(code);
if(current!=null){
if(current.getData()==null){
createHuffmanTable(current.getLeft(),"0",stringBuilder1);
createHuffmanTable(current.getRight(),"1",stringBuilder1);
}else{
huffmanCodeTable.put((char)current.getData().byteValue(),stringBuilder1.toString());
}
}
}
public String code(){
StringBuilder code= new StringBuilder();
for (char c : this.value.toCharArray()) {
String value = this.huffmanCodeTable.get(c);
code.append(value);
}
return code.toString();
}
public byte[] zip(){
String code = code();
int len=code.length()%8==0? (code.length()/8): ((code.length()/8)+1);
byte[] bytes=new byte[len];
int index=0;
for(int i=0;i<code.length();i+=8){
String substring;
if(i+8>code.length()) {
substring = code.substring(i);
}else {
substring = code.substring(i, i + 8);
}
bytes[index]=(byte) Integer.parseInt(substring,2);
index++;
}
return bytes;
}
private TNode createTree(String value) {
List<TNode> tNodes=buildNodeList(value);
while (tNodes.size()>1){
Collections.sort(tNodes);
TNode leftNode = tNodes.get(0);
TNode rightNode= tNodes.get(1);
TNode parent = new TNode(null,leftNode.getWeight()+rightNode.getWeight());
parent.setLeft(leftNode);
parent.setRight(rightNode);
tNodes.remove(leftNode);
tNodes.remove(rightNode);
tNodes.add(parent);
}
return tNodes.get(0);
}
public void preOrder(TNode current){
if(current!=null){
System.out.println(current);
preOrder(current.getLeft());
preOrder(current.getRight());
}
}
private List<TNode> buildNodeList(String value) {
byte[] bytes = value.getBytes();
List<TNode> result=new ArrayList<>();
Map<Byte,Integer> map=new HashMap<>();
for (byte aByte : bytes) {
map.merge(aByte, 1, Integer::sum);
}
if(map.size()>0){
for(Map.Entry<Byte,Integer> entry: map.entrySet()){
TNode tNode = new TNode(entry.getKey(),entry.getValue());
result.add(tNode);
}
}
return result;
}
}
class TNode implements Comparable<TNode>{
private Byte data;
private int weight;
private TNode left;
private TNode right;
public TNode(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
public Byte getData() {
return data;
}
public void setData(Byte data) {
this.data = data;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public TNode getLeft() {
return left;
}
public void setLeft(TNode left) {
this.left = left;
}
public TNode getRight() {
return right;
}
public void setRight(TNode right) {
this.right = right;
}
@Override
public int compareTo(TNode o) {
return this.weight-o.weight;
}
@Override
public java.lang.String toString() {
return "TNode{" +
"data=" + (data==null? "null":(char)data.byteValue()) +
", weight=" + weight +
'}';
}
}