📜  Java中的霍夫曼编码(1)

📅  最后修改于: 2023-12-03 15:32:02.458000             🧑  作者: Mango

Java中的霍夫曼编码

霍夫曼编码(Huffman Coding)是一种比特位压缩的算法,是一种可变字长编码(Variable Length Coding,VLC)的一种。霍夫曼编码算法通常用于数据压缩,最初用于电报员编码(Morse Code)。

实现原理

霍夫曼编码的实现过程可以分为两个步骤:创建霍夫曼树和生成霍夫曼编码。

创建霍夫曼树
  1. 统计每个字符出现的次数,并将其存储在一个优先队列中。
  2. 取出频率最小的两个节点,将它们组成一个新节点,并将频率之和作为新节点的权值。
  3. 将新节点插入优先队列中。
  4. 重复步骤2和3,直到优先队列中只剩下一个节点,也就是霍夫曼树的根节点。
生成霍夫曼编码
  1. 从根节点开始,如果向左走,则在编码末尾添加0;如果向右走,则在编码末尾添加1。
  2. 重复步骤1,直到达到叶子节点,即可得到该字符的霍夫曼编码。
代码示例
import java.util.*;

class HuffmanNode {
    int freq;
    char c;
    HuffmanNode left;
    HuffmanNode right;

    public HuffmanNode(int freq, char c) {
        this.freq = freq;
        this.c = c;
    }

    public HuffmanNode(int freq, char c, HuffmanNode left, HuffmanNode right) {
        this.freq = freq;
        this.c = c;
        this.left = left;
        this.right = right;
    }
}

class HuffmanTree {
    private PriorityQueue<HuffmanNode> queue;

    public HuffmanTree(HashMap<Character, Integer> freqMap) {
        queue = new PriorityQueue<>(Comparator.comparingInt(n -> n.freq));
        for (Map.Entry<Character, Integer> entry : freqMap.entrySet()) {
            HuffmanNode node = new HuffmanNode(entry.getValue(), entry.getKey());
            queue.add(node);
        }
        while (queue.size() > 1) {
            HuffmanNode node1 = queue.poll();
            HuffmanNode node2 = queue.poll();
            HuffmanNode newNode = new HuffmanNode(node1.freq + node2.freq, '-');
            newNode.left = node1;
            newNode.right = node2;
            queue.add(newNode);
        }
    }

    public HashMap<Character, String> getCodeMap() {
        HashMap<Character, String> map = new HashMap<>();
        if (queue.size() == 1) {
            HuffmanNode node = queue.poll();
            map.put(node.c, "0");
        } else {
            getCode("", queue.peek(), map);
        }
        return map;
    }

    private void getCode(String code, HuffmanNode node, HashMap<Character, String> map) {
        if (node == null) {
            return;
        }
        if (node.c != '-') {
            map.put(node.c, code);
        }
        getCode(code + "0", node.left, map);
        getCode(code + "1", node.right, map);
    }
}

public class Huffman {
    public static void main(String[] args) {
        String str = "Java中的霍夫曼编码";
        HashMap<Character, Integer> freqMap = new HashMap<>();
        for (char c : str.toCharArray()) {
            freqMap.put(c, freqMap.getOrDefault(c, 0) + 1);
        }
        HuffmanTree tree = new HuffmanTree(freqMap);
        HashMap<Character, String> codeMap = tree.getCodeMap();
        for (Map.Entry<Character, String> entry : codeMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

以上代码实现了从字符串生成霍夫曼编码的过程。首先,使用HashMap统计每个字符出现的次数,然后创建霍夫曼树,最后根据霍夫曼树生成霍夫曼编码。本例中的霍夫曼树使用了优先队列来实现。生成的霍夫曼编码使用了HashMap来存储,其中键为字符,值为对应的霍夫曼编码。