哈弗曼樹與哈夫曼編碼

更新、更全的《數據結構與算法》的更新網站,更有python、go、人工智能教學等着你:http://www.javashuo.com/article/p-zfinzipt-hh.htmlnode

1、什麼是哈夫曼樹(Huffman Tree)

若是咱們將百分制的考試成績轉換成五分制的成績,咱們可使用以下所示的程序:python

/* c語言實現 */

if( score < 60 )  grade =1;
else if( score < 70 ) grade =2; 
else if( score < 80 ) grade =3; 
else if( score < 90 ) grade =4;
else grade =5;

經過上述的代碼,咱們能夠構造出以下圖所示的斷定樹:算法

若是在上述五分制的成績中,咱們考慮學生成績的分佈的機率,以下圖所示:數據結構

經過學生成績分佈的機率和上述的斷定樹,咱們能夠獲得學生成績的查找效率爲:
\[ 0.05× 1+0.15 ×2+0.4× 3+0.3 ×4+0.1× 4 = 3.15 \]
從學生成績分佈的機率中,能夠看出70-79和80-89分佈中的學生較多,然而他們的查找效率確是較低的,所以咱們能夠按照以下方式修改代碼和斷定樹app

/* c語言實現 */

if( score < 80 )   
{      
  if( score < 70 );
   if( score < 60 ) {
     grade =1; 
   } else grade = 2; 
  else grad=3; 
}
else if( score < 90 ) grade =4; 
else grade =5;

經過這次修改,學生成績的查找效率爲:
\[ 0.05× 3+0.15 ×3+0.4× 2+0.3 ×2+0.1× 2 = 2.2 \]
經過上述的例子,咱們能夠思考一個問題:如何根據結點不一樣的查找頻率構造更有效的搜索樹? 網站

1.1 哈夫曼樹的定義

帶權路徑長度(WPL):設二叉樹有n個葉子結點,每一個葉子結點帶有權值\(w_k\),從根節點到每一個葉子結點的長度爲\(l_k\),則每一個葉子結點的帶權路徑長度之和就是:\(WPL = \sum_{k=1}^nw_kl_k\)ui

最優二叉樹哈夫曼樹:WPL最小的二叉樹編碼

例:有五個葉子結點,它們的權值爲 {1, 2, 3, 4, 5} ,用此權值序列能夠構造出形狀不一樣的多個二叉樹。人工智能

2、哈夫曼樹的構造

每次把權值最小的兩顆二叉樹合併

/* c語言實現 */

typedef struct TreeNode *HuffmanTree;
struct TreeNode{
  int Weight;
  HuffmanTree Left, Right;
}

HuffmanTree Huffman( MinHeap H )
{
  // 假設H->Size個權值已經存在H->Elements[]->Weight裏
  int i; HuffmanTree T;
  BuildMinHeap(H); // 將H->Elements[]按權值調整爲最小堆
  for (i = 1; i < H->Size; i++)
  {
    // 作H->Size-1次合併
    T = malloc(sizeof(struct TreeNode)); // 創建新結點
    T->Left = DeleteMin(H); // 從最小堆中刪除一個結點,做爲新T的左子結點
    T->Right = DeleteMin(H); // 從最小堆中刪除一個結點,做爲新T的右子結點
    T->Weight = T->Left->Weight+T->Right->Weight; // 計算新權值
    Insert(H, T); // 將新T插入最小堆
  }
  T = DeleteMin(H);
  return T;
}
# python語言實現

# 節點類
class Node(object):
    def __init__(self, name=None, value=None):
        self._name = name
        self._value = value
        self._left = None
        self._right = None


# 哈夫曼樹類
class HuffmanTree(object):

    # 根據Huffman樹的思想:以葉子節點爲基礎,反向創建Huffman樹
    def __init__(self, char_weights):
        self.a = [Node(part[0], part[1]) for part in char_weights]  # 根據輸入的字符及其頻數生成葉子節點
        while len(self.a) != 1:
            self.a.sort(key=lambda node: node._value, reverse=True)
            c = Node(value=(self.a[-1]._value + self.a[-2]._value))
            c._left = self.a.pop(-1)
            c._right = self.a.pop(-1)
            self.a.append(c)
        self.root = self.a[0]
        self.b = list(range(10))  # self.b用於保存每一個葉子節點的Haffuman編碼,range的值只須要不小於樹的深度就行

    # 用遞歸的思想生成編碼
    def pre(self, tree, length):
        node = tree
        if (not node):
            return
        elif node._name:
            print(node._name + '的編碼爲:')
            for i in range(length):
                print(self.b[i])
            print()
            return
        self.b[length] = 0
        self.pre(node._left, length + 1)
        self.b[length] = 1
        self.pre(node._right, length + 1)

    # 生成哈夫曼編碼   
    def get_code(self):
        self.pre(self.root, 0)


if __name__ == '__main__':
    # 輸入的是字符及其頻數
    char_weights = [('a', 5), ('b', 4), ('c', 10), ('d', 8), ('f', 15), ('g', 2)]
    tree = HuffmanTree(char_weights)
    tree.get_code()

上述過程的時間複雜度爲:O(N logN)

2.1 哈夫曼樹的特色

  • 沒有度爲1的結點;
  • n個葉子結點的哈夫曼樹共有2n-1個結點

  • 哈夫曼樹的任意非葉結點的左右子樹交換後還是哈夫曼樹;
  • 對同一組權值 \({W_1, W_2, \cdots, W_n}\),是否存在不一樣構的兩顆哈夫曼樹呢?
    • 對一組權值 {1, 2, 3, 3},能夠有以下圖所示的不一樣構的兩顆哈夫曼樹:

3、哈夫曼編碼

給定一段字符串,如何對字符進行編碼,可使得該字符串的編碼存儲空間最少

例:假設有一段文本,包含58個字符,並由如下7個字符構成:a,e,i,s,t,空格(sp),換行(nl)。這7個字符出現的次數不一樣。如何對這7個字符進行編碼,使得總編碼空間最少?

分析:

  1. 用等長ASCCII編碼:58*8 = 464位;
  2. 用等長3位編碼:58*3 = 174位;
  3. 不等長編碼:出現頻率高的字符用的編碼短些,出現頻率低的字符能夠編碼長些?

對於上述問題,咱們若是使用下圖所示方式進行不等長編碼:

很明顯,能夠發現上圖所示的不等長編碼具備二義性,所以咱們可使用前綴碼的方式解決二義性問題。

前綴碼(prefix code):任何字符的編碼都不是另外一字符編碼的前綴。

3.1 使用二叉樹編碼

使用二叉樹編碼,咱們須要注意如下兩個問題:

  1. 左右分支:0、1
  2. 字符只在葉結點上

假設四個字符的頻率爲:a:4,u:1,x:2,z:1;那麼咱們可使用最普通的二叉樹對這四個字符進行編碼,以下圖所示:

經過上圖能夠發現,咱們使用最偷懶的方式,把四個字符放在上述二叉樹的四個葉子結點上,所以咱們能夠考慮使用以下所示的方法,下降二叉樹的編碼代價

綜上:哈夫曼編碼須要解決的一個問題爲——如何構造一顆編碼代價最小的二叉樹。

3.2 使用哈夫曼樹編碼

對於咱們提出來的7個字符的例子,若是咱們得知這7個字符的分佈機率爲以下圖所示:

咱們可使用構造哈夫曼樹的方式,進行哈夫曼編碼,編碼流程以下:

最終結果以下圖所示:

相關文章
相關標籤/搜索