哈夫曼编码 java实现

/**
 * @author Yoshino
 * 实现赫夫曼编码
 */
public class HuffmanCode {
    static Map<Byte, String> codeMap = new HashMap<>();

    public static void main(String[] args) {
        String content = "i like like like java do you like a java";
        byte[] bytes = content.getBytes();
        byte[] huffmanZip = huffmanZip(bytes);
        System.out.println(Arrays.toString(huffmanZip));
    }
   public static byte[] huffmanZip(byte[] bytes)
   {

       //1创建哈夫曼树
        //1.1 得到节点链表
       List<HuffmanCodeNode> nodes = getNodes(bytes);
        //1.2 得到哈夫曼数的根节点
       HuffmanCodeNode root = getHuffmanTree(nodes);
       //2.获取哈夫曼编码
       StringBuilder builder = new
               StringBuilder();
       getNodeCode(root, "", builder);
       //3.用哈夫曼编码来编码原始的数据
       StringBuilder s = new StringBuilder();
       for (byte b:bytes)
       {
           s.append(codeMap.get(b));
       }
       //4.压缩,得到压缩后的数据
       return zip(s.toString());
   }

    /**
     * 构造赫夫曼树节点
     * @param bytes
     * @return 赫夫曼树节点的链表
     */
    public static List<HuffmanCodeNode> getNodes(byte[] bytes) {
        List<HuffmanCodeNode> nodes = new LinkedList<>();

        Map<Byte, Integer> nodeMap = new HashMap<>();
        for (byte b : bytes) {
            //记录每个数据出现的次数,作为节点的权重
            nodeMap.put(b, nodeMap.getOrDefault(b, 0) + 1);
        }
        //遍历封装成HuffmanCodeNode
        for (Map.Entry<Byte, Integer> entry : nodeMap.entrySet()) {
            nodes.add(new HuffmanCodeNode(entry.getKey(), entry.getValue()));
        }
        return nodes;
    }

    /**
     * 构造赫夫曼树
     * @param nodes
     * @return 哈夫曼树的根节点
     */
    public static HuffmanCodeNode getHuffmanTree(List<HuffmanCodeNode> nodes) {
        while (nodes.size() > 1) {
            //排序
            Collections.sort(nodes);
            //每次取出最小的两个
            HuffmanCodeNode left = nodes.get(0);
            HuffmanCodeNode right = nodes.get(1);
            //构造新的节点
            HuffmanCodeNode root = new HuffmanCodeNode(null, left.weight + right.weight);
            root.left = left;
            root.right = right;
            nodes.remove(left);
            nodes.remove(right);
            nodes.add(root);
        }
        return nodes.get(0);
    }

    /**
     * 获取节点对应的哈夫曼编码
     * @param node 进行编码的节点
     * @param singleCode 0,1 向左遍历为0 向右遍历为1
     * @param s 最终的该节点的编码
     */
    public static void getNodeCode(HuffmanCodeNode node, String singleCode, StringBuilder s) {
        StringBuilder stringBuilder = new StringBuilder(s);
        stringBuilder.append(singleCode);
        if (node != null) {
            //data!=null 说明为叶子节点 即为原始数据
            if (node.data != null) {
                codeMap.put(node.data, stringBuilder.toString());
            } else {
                //data == null 说明为哈夫曼树中我们人为构造出来的节点,继续进行编码
                getNodeCode(node.left, "0", stringBuilder);
                getNodeCode(node.right, "1", stringBuilder);
            }
        }
    }

    /**
     * 将编码后的二进制字符串压缩为byte数组
     * @param byteStr 编码后的二进制字符串
     * @return 压缩后的byte数组
     */
    public static byte[] zip(String byteStr){
        int len;
        int index = 0;
        StringBuilder s = new StringBuilder(byteStr);
        //每8位为一个子节
        if (byteStr.length()%8 ==0)
        {
            len = byteStr.length()/8;
        }else
        {
            len = byteStr.length()/8 + 1;
        }
        byte[] zipBytes = new byte[len];
        for (int i = 0; i < byteStr.length(); i +=8) {
            String substring;
            //当长度足够截取8位时,直接截取
            if (i+8 <= byteStr.length())
            {
                substring = s.substring(i, i + 8);
            }else
                //长度不足8位时,截取到最后
            {
                substring = s.substring(i);
            }
            zipBytes[index]  = (byte) Integer.parseInt(substring,2);
            index++;
        }
        return zipBytes;
    }


}

class HuffmanCodeNode implements Comparable<HuffmanCodeNode> {
    Byte data;
    int weight;
    HuffmanCodeNode left;
    HuffmanCodeNode right;

    public HuffmanCodeNode(Byte data, int weight) {
        this.data = data;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "HuffmanCodeNode{" +
                "data=" + data +
                ", weight=" + weight +
                '}';
    }

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

    @Override
    public int compareTo(HuffmanCodeNode o) {
        return this.weight - o.weight;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值