Java數據結構和算法(四)赫夫曼樹

Java數據結構和算法(四)赫夫曼樹

數據結構與算法目錄(http://www.javashuo.com/article/p-qvigrlkr-da.html)html

赫夫曼樹又稱爲最優二叉樹,赫夫曼樹的一個最主要的應用就是赫夫曼編碼。java

1、赫夫曼編碼

can you can a can as a can canner can a can.

1.1 定長編碼

99 97 110 32 121 111 117 32 99 97 110 32 97 32 99 97 110 32 97 115 32 97 32 99 97 110 32 99 97 110 110 101 114 32 99 97 110 32 97 32 99 97 110 46

1100011 1100001 1101110 100000 1111001 1101111 1110101 100000 1100011 1100001 1101110 100000 1100001 100000 1100011 1100001 1101110 100000 1100001 1110011 100000 1100001 100000 1100011 1100001 1101110 100000 1100011 1100001 1101110 1101110 1100101 1110010 100000 1100011 1100001 1101110 100000 1100001 100000 1100011 1100001 1101110

定長編碼長度:8 * 44 = 352算法

1.2 變長編碼

定長編碼雖然簡單,但實際上有的字符出現的頻率高有的低,能夠將出現頻率高的編碼設置的短些,頻率低的設置的長些,這樣編碼後的長度也會減小。數組

// 每一個字符出現的頻率
r:1 s:1 u:1 e:1 y:1 .:1 o:1 c:7 n:8  :11 a:11

0=a,1= ,10=n,11=c,100=o,101=.,110=y,111=e,1000=u,1001=s,1010=r
11 0 10 1 1010 100 1000 1 11 0 10 1 0 1 11 0 10 1 0 1001 1 0 1 11 0 10 1 11 0 10 10 111 1010 1 11 0 10 1 0 1 11 0 10 101

採用上述編碼雖然減小了長度,但沒法解碼。如 1 究竟是 , n, c, o ... 沒法肯定。數據結構

字符的編碼都不能是其餘字符編碼的前綴,符合此要求的編碼叫作前綴編碼。數據結構和算法

1.3 赫夫曼編碼

// 每一個字符出現的頻率
r:1 s:1 u:1 e:1 y:1 .:1 o:1 c:7 n:8  :11 a:11

10=a,01= ,00=n,111=c,11000=o,110011=.,110010=y,110101=e,110100=u,110111=s,110110=r
111 10 00 01 110010 11000 110100 01 111 10 00 01 10 01 111 10 00 01 10 110111 01 10 01 111 10 00 01 111 10 00 00 110101 110110 01 111 10 00 01 10 01 111 10 00 11001

赫夫曼編碼樹

2、赫夫曼樹概念

給定 n 個權值做爲 n 個葉子結點,構造一棵二叉樹,若樹的帶權路徑長度達到最小,則這棵樹被稱爲赫夫曼樹。編碼

赫夫曼樹

2.1 路徑和路徑長度

在一棵樹中,從一個結點往下能夠達到的孩子或孫子結點之間的通路,稱爲路徑。通路中分支的數目稱爲路徑長度。若規定根結點的層數爲 1,則從根結點到第 L 層結點的路徑長度爲 L - 1。3d

例如上圖左樹:100 和 80 的路徑長度是 1,50 和 30 的路徑長度是 2,20 和 10 的路徑長度是 3。code

2.2 結點的權及帶權路徑長度

定義:若將樹中結點賦給一個有着某種含義的數值,則這個數值稱爲該結點的權。結點的帶權路徑長度爲:從根結點到該結點之間的路徑長度與該結點的權的乘積。htm

例如上圖左樹:節點 20 的路徑長度是 3,它的帶權路徑長度 = 路徑長度 * 權 = 3 * 20 = 60。

2.3 樹的帶權路徑長度

定義:樹的帶權路徑長度規定爲全部葉子結點的帶權路徑長度之和,記爲 WPL。

例如上圖右樹:樹的 WPL= 1 * 100 + 2 * 50 + 3* 20 + 3 * 10 = 290
例如上圖左樹:樹的 WPL= 2 * 100 + 2 * 50 + 2 * 20 + 2 * 10 = 360

左邊的樹 WPL > 右邊的樹的 WPL。你也能夠計算除上面兩種示例以外的狀況,但實際上右邊的樹就是 {10, 20, 50, 100} 對應的哈夫曼樹。至此,應該堆哈夫曼樹的概念有了必定的瞭解了,下面看看如何去構造一棵哈夫曼樹。

3、赫夫曼樹基本操做

將一個普通的數組轉換爲赫夫曼樹。基本原理:將數組排序後取出兩個最小權值的節點造成新的節點,新節點的權值爲這兩個節點權值之和,而後不斷輪詢造成新的節點。

public static TreeNode<Integer> huffman(int[] arr) {
    List<TreeNode<Integer>> huffmanTree = new ArrayList<>();
    for (int i : arr) {
        huffmanTree.add(new TreeNode(i));
    }
    while (huffmanTree.size() > 1) {
        // 1. 排序
        Collections.sort(huffmanTree, (TreeNode<Integer> o1, TreeNode<Integer> o2) -> {
            return o1.getValue() - o2.getValue();
        });
        // 2. 取出最小的 2 個數造成一個新的節點
        TreeNode<Integer> left = huffmanTree.remove(0);
        TreeNode<Integer> right = huffmanTree.remove(0);
        TreeNode<Integer> head = new TreeNode(left.getValue() + right.getValue());
        head.setLeft(left);
        head.setRight(right);
        huffmanTree.add(head);
    }
    return huffmanTree.get(0);
}

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索