1. 程式人生 > 實用技巧 >10: java資料結構和演算法: 構建哈夫曼樹, 獲取哈夫曼編碼, 使用哈夫曼編碼原理對檔案壓縮和解壓

10: java資料結構和演算法: 構建哈夫曼樹, 獲取哈夫曼編碼, 使用哈夫曼編碼原理對檔案壓縮和解壓

最終結果哈夫曼樹,如圖所示:

直接上程式碼:

public class HuffmanCode {
    public static void main(String[] args) {
        //獲取哈夫曼樹並顯示
        Hnode root = createHuffmanTree(createNodes());
        root.beforePrint();
        System.out.println("====================");
        //從哈夫曼樹中讀取 哈夫曼編碼
        getHuffmanCode(root);
        //從huffmanCodes 中讀取哈夫曼編碼:A:10, B:01, C:0011,D:11,E:000,F:00100,G:00101
        System.out.println("哈夫曼編碼為:"+huffmanCodes);
    }

    //建立一個 Hnode節點的集合
    public static List<Hnode> createNodes(){
        List<Hnode> nodes = new ArrayList<Hnode>();
        nodes.add(new Hnode(new Person(12,"A"),60));
        nodes.add(new Hnode(new Person(13,"B"),45));
        nodes.add(new Hnode(new Person(14,"C"),13));
        nodes.add(new Hnode(new Person(15,"D"),69));
        nodes.add(new Hnode(new Person(16,"E"),14));
        nodes.add(new Hnode(new Person(17,"F"),5));
        nodes.add(new Hnode(new Person(18,"G"),3));
        return nodes;
    }
    //根據list 建立哈夫曼樹
    public static Hnode createHuffmanTree(List<Hnode> nodes){
        while(nodes.size() > 1){
            //先對 nodes進行從小到大排序, 根據權重值進行從小到大排序
            Collections.sort(nodes, new Comparator<Hnode>() {
                public int compare(Hnode o1, Hnode o2) {
                    return o1.weight - o2.weight;
                }
            });
            //取出前二個最小的元素,構建一個父節點只有權重 沒有資料的二叉樹
            Hnode leftNode = nodes.get(0);
            Hnode rightNode = nodes.get(1);
            Hnode parent = new Hnode(null, leftNode.weight + rightNode.weight);
            parent.leftNode = leftNode;
            parent.rightNode = rightNode;

            //將原來nodes中已經處理的前二個最小元素刪除調,並將parent節點存入nodes中
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            nodes.add(parent);
        }
        //迴圈結束時候,nodes中只有一個節點了,且該節點就是哈夫曼樹的根節點
        return nodes.get(0);
    }

    static StringBuilder stringBuilder = new StringBuilder();
    static Map<String,String> huffmanCodes = new HashMap<String, String>();
    //從哈夫曼樹中讀取 哈夫曼編碼: A:10, B:01, C:0011,D:11,E:000,F:00100,G:00101
    public static void getHuffmanCode(Hnode root){
        if (root == null) {
            return ;
        }
        getCode(root.leftNode,"0",stringBuilder);
        getCode(root.rightNode,"1",stringBuilder);
    }

    private static void getCode(Hnode node, String code, StringBuilder builder) {
        StringBuilder builder1 = new StringBuilder(builder);
        builder1.append(code);
        if (node != null) {
            if (node.person == null) {
                //如果資料為不null,說明是子節點
                //左遞迴處理
                getCode(node.leftNode,"0",builder1);
                //右遞迴處理
                getCode(node.rightNode,"1",builder1);
            }else{
                //如果資料為null,說明是葉子節點
                huffmanCodes.put(node.person.name,builder1.toString());
            }
        }
    }
}



//先建節點
class Hnode{
    Person person;//資料
    int weight;//權重
    Hnode leftNode;
    Hnode rightNode;

    public Hnode(Person person, int weight) {
        this.person = person;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Hnode{" +
                "data='" + person + '\'' +
                ", weight=" + weight +
                '}';
    }
    //前序遍歷
    public void beforePrint(){
        System.out.println(this);
        if (this.leftNode != null) {
            this.leftNode.beforePrint();
        }
        if (this.rightNode != null) {
            this.rightNode.beforePrint();
        }
    }
}

class Person {
    int age;
    String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

結果如下: