贪心算法-03哈夫曼编码问题
生活随笔
收集整理的這篇文章主要介紹了
贪心算法-03哈夫曼编码问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
哈夫曼編碼
- 簡介
- 哈夫曼編碼是一種字符編碼方式,可以對指定的字符集進行數據壓縮,壓縮率在20%到90%。
- 問題描述
- 現在有一個包含5個字符{A,B,C,D,E},各個字符的出現頻率依次為{0.35, 0.1, 0.2, 0.2, 0.15}。需要構造一種有效的編碼類型,使用該編碼表達以上字符表時可以產生平均長度最短的位串。
- 問題分析
- n個字符組成的文本編碼時有兩種方式,定長編碼(為每個字符賦予一個長度固定為m,m>=log_2^n的位串,ASCII碼就是如此的)和變長編碼(長度各異的編碼,其中出現頻率高的采用較短的編碼表示,摩斯電嗎就是如此做的)。通常,為了提高效率一般使用定長編碼,但是定長編碼會遇到一個問題,就是前綴碼問題。所謂前綴碼,就是對任意字符使用01串表示其,并且任何一個字符的編碼不是其他字符的前綴。有了前綴碼,就可以在位串中準確定位字符,快速替換文本了。
- 哈夫曼提出來這種編碼策略,稱為哈夫曼編碼。其核心就是利用二叉樹這種數據結構。(前綴碼是簡單路徑的節點值得來的,是通過從一個葉子節點到另一個葉子節點的簡單路徑不存在來保證的。
- 這樣的二叉樹稱為哈夫曼樹,算法如下。
- 初始化n個單節點的樹,并標上字母表中字符。把每個字符的頻率記錄在對應的根節點中,用來標記樹的權重,即樹的權重為所有節點的概率和。
- 重復下面的步驟,直到只剩下一棵單獨的樹。找到兩課權重最小的樹,若權重相同,任選其中一個,分別把它們作為新二叉樹的左右子樹,并將其權重之和作為新的權重記錄根節點中。
- 這樣的樹就是哈夫曼樹,獲得樹后依據左分支為0,右分支為1,可以得到編碼。
- 對題目的例子,哈夫曼編碼節約了25%的存儲空間。
- 對貪心選擇性質和最優子結構性質理解不難,這里不做證明了。
- 代碼
- # -*-coding:utf-8-*-class Node(object):def __init__(self, freq):self.left = Noneself.right = Noneself.father = Noneself.freq = freqdef is_left(self):return self.father.left == selfdef __str__(self):return str(self.freq)def create_nodes(freqs):"""創建葉子節點:param freqs::return:"""return [Node(freq) for freq in freqs]def create_huffman_tree(nodes):queue = nodes[:]while len(queue) > 1:queue.sort(key=lambda item: item.freq)node_left = queue.pop(0)node_right = queue.pop(0)node_father = Node(node_left.freq+node_right.freq)node_father.left = node_leftnode_father.right = node_rightnode_left.father = node_fathernode_right.father = node_fatherqueue.append(node_father)queue[0].father = Nonereturn queue[0]def huffman_encoding(nodes, root):codes = [''] * len(nodes)for i in range(len(nodes)):node_tmp = nodes[i]while node_tmp != root:if node_tmp.is_left():codes[i] = '0' + codes[i]else:codes[i] = '1' + codes[i]node_tmp = node_tmp.fatherreturn codesif __name__ == '__main__':chars_freq = [('A', 35), ('B', 10), ('C', 20), ('D', 20), ('E', 15)]nodes = create_nodes([item[1] for item in chars_freq])root = create_huffman_tree(nodes)codes = huffman_encoding(nodes, root)for item in zip(chars_freq, codes):print('Char:{}freq:{}encoding:{}'.format(item[0][0], item[0][1], item[1]))
- 運行結果
- 補充說明
- 具體代碼可以查看我的Github,歡迎Star或者Fork
- 參考書《你也能看得懂的Python算法書》
總結
以上是生活随笔為你收集整理的贪心算法-03哈夫曼编码问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贪心算法-02活动安排问题
- 下一篇: 分治算法-01连续子序列的最大和问题