Java統計文本字符的哈弗曼編碼

先從文本讀取字符,統計字符出現的次數用map保存,然后根據詞頻計算每個字符的哈弗曼編碼,哈弗曼樹的建立過程就是每次取兩個權值最小的節點生成新的節點,根據建立的哈弗曼樹計算每個字符的哈弗曼編碼,如果當前節點在父節點的左邊,當前節點的編碼為0,否則為1,最后從上往下記錄哈弗曼編碼.代碼如下,代碼注釋很詳細.

HuffmanTree.java
import java.util.*;

public class HuffmanTree {
    class Node {
        int val;
        int weight;
        Node left;
        Node right;
        Node parent;

        Node(int weight) {
            this.weight = weight;
        }
    }

    /**
     * 計算哈弗曼編碼
     *
     * @param counter key為對應的字符,value為字符出現的次數
     * @return 返回一個map, key為字符, value為對應的哈弗曼編碼
     */
    public Map<Integer, String> getHuffmanCode(Map<Integer, Integer> counter) {
        //根據權重排序建立一個優先隊列來保存節點,方便每次取最小的兩個節點
        PriorityQueue<Node> priorityQueue = new PriorityQueue<>(
                new Comparator<Node>() {
                    @Override
                    public int compare(Node o1, Node o2) {
                        return o1.weight - o2.weight;
                    }
                }
        );
        //用數組保存哈弗曼樹, 哈弗曼數的度為0的節點為counter.size(), 度為1的節點為0
        //度為2的葉子節點為counter.size() - 1
        Node[] huffmanTree = new Node[counter.size() * 2 - 1];
        int index = 0;
        //把葉子節點放在數組前面的counter.size()個位置
        for (Map.Entry<Integer, Integer> entry : counter.entrySet()) {
            huffmanTree[index] = new Node(entry.getValue());
            huffmanTree[index].val = entry.getKey();
            priorityQueue.add(huffmanTree[index]);
            index++;
        }

        //每次從優先隊列中取權重最小的兩個節點生成新的父節點
        for (int i = counter.size(); i < huffmanTree.length; i++) {
            Node n1 = priorityQueue.poll();
            Node n2 = priorityQueue.poll();
            huffmanTree[i] = new Node(n1.weight + n2.weight);
            huffmanTree[i].left = n1;
            huffmanTree[i].right = n2;
            n1.parent = huffmanTree[i];
            n2.parent = huffmanTree[i];
            priorityQueue.add(huffmanTree[i]);
        }

        //levelTraverse(huffmanTree);
        //保存每個字符的哈弗曼編碼
        Map<Integer, String> res = new HashMap<>();
        //計算每個字符的哈弗曼值
        StringBuilder huffmanCode = new StringBuilder();
        Node parent, curNode;
        for (int i = 0; i < counter.size(); i++) {
            huffmanCode.setLength(0);
            curNode = huffmanTree[i];
            parent = huffmanTree[i].parent;
            //從下往上計算huffmanTree[i].val的的哈弗曼編碼
            while (parent != null) {
                //當前節點在父節點的左邊,哈弗曼編碼為0,在右邊為1
                if (parent.left == curNode) {
                    huffmanCode.append("0");
                } else {
                    huffmanCode.append("1");
                }
                curNode = parent;
                parent = parent.parent;
            }
            //因為是從下往上生成的,所以需要逆置一下
            huffmanCode.reverse();
            res.put(huffmanTree[i].val, huffmanCode.toString());
        }
        return res;
    }

    /**
     * 從上往下打印哈弗曼數的權值,調試用
     *
     * @param huffamanTree
     */
    private void levelTraverse(Node[] huffamanTree) {
        for (int i = huffamanTree.length - 1; i >= 0; i--) {
            System.out.print(huffamanTree[i].weight + " ");
        }
        System.out.println("");
    }
}
TestHuffmanTree.java
import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class TestHuffmanTree {
    public static void main(String[] args) throws IOException {
        //統計每個字符出現的次數
        BufferedReader bis = null;
        try {
            bis = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Map<Integer, Integer> counter = new HashMap<>();
        while (true) {
            int k = bis.read();
            if (k == -1) {
                break;
            }
            counter.putIfAbsent(k, 0);
            counter.put(k, counter.get(k) + 1);
        }
        System.out.println("字符頻率為:");
        System.out.println(counter);
        HuffmanTree huffmanTree = new HuffmanTree();
        Map<Integer, String> huffmanCodes = huffmanTree.getHuffmanCode(counter);
        System.out.println("哈弗曼編碼為:");
        System.out.println(huffmanCodes);
    }

}
input.txt
abbcccddddeeeee
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容