哈夫曼编码huffmanCoding

该代码示例展示了如何使用Java实现Huffman编码和解码。首先创建一个Huffman树,基于输入字符串的字符频率,然后进行编码和解码操作。编码过程通过遍历二叉树生成编码字典,解码则依赖于反转的编码字典。

 自用保存

import java.util.*;

class Huffman {
    public static void main(String[] args) {
        HuffmanTree huffmanTree = new HuffmanTree("bibbity_bobbity");
        huffmanTree.createTree();
        String encoded = huffmanTree.encode();
        System.out.println("Encoded String: " + encoded);
        System.out.println("Decoded String: " + huffmanTree.decode(encoded));
    }
}

class TreeNode {
    String letter = "";
    int frequency = 0;
    TreeNode left = null, right = null;

    public TreeNode(String letter, int frequency) {
        this.letter = letter;
        this.frequency = frequency;
    }

    public TreeNode(int frequency, TreeNode left, TreeNode right) {
        this.frequency = frequency;
        this.left = left;
        this.right = right;
    }
}

class HuffmanTree {
    private Map<String, Integer> frequencyMap = new HashMap<>();
    private Map<String, String> codeBook = new HashMap<>()  ,   reverseCodeBook = new HashMap<>();
    private TreeNode root;
    private String stringToEncode;

    public HuffmanTree(String stringToEncode) {
        this.stringToEncode = stringToEncode;
    }

    public void createTree() {
        // 记录频次
        for (int i = 0; i < stringToEncode.length(); i++) {
            String key = Character.toString(stringToEncode.charAt(i));
            if (!frequencyMap.containsKey(key)) {
                frequencyMap.put(key, 1);
            } else {
                int frequency = frequencyMap.get(key) + 1;
                frequencyMap.replace(key, frequency);
            }
        }
        // ComparingInt(o -> o.frequency) 默认升序
        // 如Queue<int[]> minHeap = new PiorityQueue<>(Comparator.comparingInt(a -> a[1]));
        Queue<TreeNode> pq = new PriorityQueue<>(Comparator.comparingInt(o -> o.frequency));
        for (Map.Entry<String, Integer> m : frequencyMap.entrySet()) {
            pq.add(new TreeNode(m.getKey(), m.getValue()));
        }
        while (pq.size() > 1) {
            TreeNode left = pq.remove();
            TreeNode right = pq.remove();
            pq.add(new TreeNode(left.frequency + right.frequency, left, right));
        }
        root = pq.remove();
    }

    /***
     *
     * @param node 节点
     * @param code 每个叶子节点的编码
     */
    private void traverse(TreeNode node, StringBuilder code) {
        if (node.left == null && node.right == null) { // 到达叶子节点 放入codeBook(它是个map)
            codeBook.put(node.letter, code.toString());
        }
        if (node.left != null) {
            traverse(node.left, code.append(0));
            code.deleteCharAt(code.length() - 1);
        }
        if (node.right != null) {
            traverse(node.right, code.append(1));
            code.deleteCharAt(code.length() - 1);
        }
    }

    public void printCodeBook() {
        System.out.println("Code Book");
        for (Map.Entry<String, String> m : codeBook.entrySet()) {
            System.out.println(m.getKey() + "\t" + m.getValue());
        }
        System.out.println();
    }

    private void CodeBookReverse() {
        for (Map.Entry<String, String> m : codeBook.entrySet()) {
            reverseCodeBook.put(m.getValue(), m.getKey());
        }
    }

    /***
     * 编码
     * @return 返回编码串
     */
    public String encode() {
        traverse(root, new StringBuilder());
        StringBuilder encode = new StringBuilder();
        // 遍历句子中的每个字母 对照codeBook翻译为bit码
        for (int i = 0; i < stringToEncode.length(); i++) {
            String k = Character.toString(stringToEncode.charAt(i));
            encode.append(codeBook.get(k));
        }
        printCodeBook();
        return encode.toString();
    }

    /***
     * 当key = "0"时 检测到字典中有相对的字母 直接编码  (此时encoded串循环到"0")
     * 然后key清空 直到下一轮读入"111"  (此时encoded串循环到"0111")
     * key清空 直到下一轮读到"0" (此时encoded串循环到"01110")
     * @param encoded 已经编码的串
     * @return 返回解码串
     */
    public String decode(String encoded) {
        StringBuilder decoded = new StringBuilder()  ,   key = new StringBuilder();
        CodeBookReverse(); // 填写reverseCodeBook 相当于把codeBook里面的键和值对调
        for (int i = 0; i < encoded.length(); i++) {
            key = key.append(encoded.charAt(i));
            if (reverseCodeBook.containsKey(key.toString())) {
                decoded.append(reverseCodeBook.get(key.toString()));
                key = new StringBuilder(); // 这一步相当于某个bit编码被采用后直接丢弃
            }
        }
        return decoded.toString();
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值