Python完成哈夫曼樹編碼過(guò)程及原理詳解
哈夫曼樹原理
秉著能不寫就不寫的理念,關(guān)于哈夫曼樹的原理及其構(gòu)建,還是貼一篇博客吧。
http://www.dhdzp.com/article/97396.htm
其大概流程

哈夫曼編碼代碼
# 樹節(jié)點(diǎn)類構(gòu)建
class TreeNode(object):
def __init__(self, data):
self.val = data[0]
self.priority = data[1]
self.leftChild = None
self.rightChild = None
self.code = ""
# 創(chuàng)建樹節(jié)點(diǎn)隊(duì)列函數(shù)
def creatnodeQ(codes):
q = []
for code in codes:
q.append(TreeNode(code))
return q
# 為隊(duì)列添加節(jié)點(diǎn)元素,并保證優(yōu)先度從大到小排列
def addQ(queue, nodeNew):
if len(queue) == 0:
return [nodeNew]
for i in range(len(queue)):
if queue[i].priority >= nodeNew.priority:
return queue[:i] + [nodeNew] + queue[i:]
return queue + [nodeNew]
# 節(jié)點(diǎn)隊(duì)列類定義
class nodeQeuen(object):
def __init__(self, code):
self.que = creatnodeQ(code)
self.size = len(self.que)
def addNode(self,node):
self.que = addQ(self.que, node)
self.size += 1
def popNode(self):
self.size -= 1
return self.que.pop(0)
# 各個(gè)字符在字符串中出現(xiàn)的次數(shù),即計(jì)算優(yōu)先度
def freChar(string):
d ={}
for c in string:
if not c in d:
d[c] = 1
else:
d[c] += 1
return sorted(d.items(),key=lambda x:x[1])
# 創(chuàng)建哈夫曼樹
def creatHuffmanTree(nodeQ):
while nodeQ.size != 1:
node1 = nodeQ.popNode()
node2 = nodeQ.popNode()
r = TreeNode([None, node1.priority+node2.priority])
r.leftChild = node1
r.rightChild = node2
nodeQ.addNode(r)
return nodeQ.popNode()
codeDic1 = {}
codeDic2 = {}
# 由哈夫曼樹得到哈夫曼編碼表
def HuffmanCodeDic(head, x):
global codeDic, codeList
if head:
HuffmanCodeDic(head.leftChild, x+'0')
head.code += x
if head.val:
codeDic2[head.code] = head.val
codeDic1[head.val] = head.code
HuffmanCodeDic(head.rightChild, x+'1')
# 字符串編碼
def TransEncode(string):
global codeDic1
transcode = ""
for c in string:
transcode += codeDic1[c]
return transcode
# 字符串解碼
def TransDecode(StringCode):
global codeDic2
code = ""
ans = ""
for ch in StringCode:
code += ch
if code in codeDic2:
ans += codeDic2[code]
code = ""
return ans
# 舉例
string = "AAGGDCCCDDDGFBBBFFGGDDDDGGGEFFDDCCCCDDFGAAA"
t = nodeQeuen(freChar(string))
tree = creatHuffmanTree(t)
HuffmanCodeDic(tree, '')
print(codeDic1,codeDic2)
a = TransEncode(string)
print(a)
aa = TransDecode(a)
print(aa)
print(string == aa)
接下來(lái)就是一段一段分析代碼
1.樹結(jié)點(diǎn)類的構(gòu)建:
共有5個(gè)屬性:結(jié)點(diǎn)的值,結(jié)點(diǎn)的優(yōu)先度,結(jié)點(diǎn)的左子結(jié)點(diǎn),結(jié)點(diǎn)的右子結(jié)點(diǎn),結(jié)點(diǎn)值的編碼(這個(gè)沒有什么好說(shuō)的,這些屬性都是被需要的)
2.創(chuàng)建樹結(jié)點(diǎn)隊(duì)列函數(shù):
對(duì)于所有的字母結(jié)點(diǎn),我們將其組成一個(gè)隊(duì)列,這里使用list列表來(lái)完成隊(duì)列的功能。將所有樹節(jié)點(diǎn)夠放進(jìn)列表中,當(dāng)然傳進(jìn)來(lái)的是按優(yōu)先度從小到大已排序的元素列表
3.為隊(duì)列添加節(jié)點(diǎn)元素,并保證優(yōu)先度從大到小排列:
當(dāng)有新生成的結(jié)點(diǎn)時(shí),需將其插入列表,并放在合適位置,使隊(duì)列依然時(shí)按優(yōu)先度從小打到排列的。
4.結(jié)點(diǎn)隊(duì)列類定義:
創(chuàng)建類初始化時(shí)需要傳進(jìn)去的是一個(gè)列表,列表中的每個(gè)元素是由字母與優(yōu)先度組成的元組。元組第一個(gè)元素是字母,第二個(gè)元素是優(yōu)先度(即在文本中出現(xiàn)的次數(shù))
類初始化化時(shí),調(diào)用“創(chuàng)建樹結(jié)點(diǎn)隊(duì)列函數(shù)”,隊(duì)列中的每個(gè)元素都是一個(gè)樹結(jié)點(diǎn)。
類中還包含一個(gè)隊(duì)列規(guī)模屬性以及另外兩個(gè)操作函數(shù):添加結(jié)點(diǎn)函數(shù)和彈出結(jié)點(diǎn)函數(shù)。
添加結(jié)點(diǎn)函數(shù)直接調(diào)用之前定義的函數(shù)即可,輸入的參數(shù)為隊(duì)列和新結(jié)點(diǎn),并且隊(duì)列規(guī)模加一
彈出第一個(gè)元素則直接調(diào)用列表的pop(0)函數(shù),同時(shí)隊(duì)列規(guī)模減一
5.計(jì)算文本中個(gè)字母的優(yōu)先度,即出現(xiàn)的次數(shù):
定義一個(gè)字典,遍歷文本中的每一個(gè)字母,若字母不在字典里說(shuō)明是第一次出現(xiàn),則定義該字母為鍵,另鍵值為1,若在字典里有,則只需將相應(yīng)的鍵值加一。 遍歷后就得到了每個(gè)字母出現(xiàn)的次數(shù)。
6.由哈夫曼樹得到編碼表:
這里定義了兩個(gè)全局字典,用于存放字母編碼,一個(gè)字典用于編碼,另一個(gè)字典用于解碼,這樣程序操作起來(lái)比較方便。
這里主要就是遍歷,運(yùn)用的是二叉樹的中序遍歷。如果明白中序遍歷的化,就能看懂這里的代碼,每遞歸到深一層的時(shí)候,就在后面多加一個(gè)‘0'(左子樹)或‘1'(右子樹)。
中序遍歷我在上一篇博客中講的還算可以吧,不懂的可以參考一下,否則就可以略過(guò)這一段。
這一段是哈夫曼編碼的關(guān)鍵,也是難點(diǎn),希望能夠好好理解一下,也是對(duì)遞歸的一個(gè)理解。這一點(diǎn)沒問(wèn)題的話,我覺得哈夫曼樹真的挺簡(jiǎn)單的!?。?/p>
7.字符串編碼,字符串解碼:
這兩段我就不詳細(xì)說(shuō)了,應(yīng)為已經(jīng)有編碼與解碼的字典了,所以對(duì)應(yīng)每一個(gè)字母直接在字典里找就好了,而且字典的尋找速度還是相當(dāng)快的。
差不多了,例子就不舉了,確實(shí)哈夫曼樹比之前的什么八皇后問(wèn)題還有KMP問(wèn)題簡(jiǎn)單多了。
最后向Huffman大神致敬,祝各位學(xué)有所成。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python的即時(shí)標(biāo)記項(xiàng)目練習(xí)筆記
這篇文章主要介紹了python的即時(shí)標(biāo)記項(xiàng)目練習(xí)筆記,本文是閱讀《python基礎(chǔ)教程》一書的動(dòng)手實(shí)踐項(xiàng)目,需要的朋友可以參考下2014-09-09
Python:一行代碼,導(dǎo)入Python所有庫(kù)
在本篇內(nèi)容里小編給大家分享如何用一行代碼,導(dǎo)入Python所有庫(kù),有需要的朋友們可以學(xué)習(xí)下,希望能夠給你帶來(lái)幫助2021-10-10
python通過(guò)cmd創(chuàng)建虛擬環(huán)境的實(shí)現(xiàn)(pip方式)
Python的虛擬環(huán)境是正常的現(xiàn)實(shí)環(huán)境相對(duì)應(yīng)的,在虛擬環(huán)境中安裝的包是與現(xiàn)實(shí)環(huán)境隔離的,本文主要介紹了python通過(guò)cmd創(chuàng)建虛擬環(huán)境的實(shí)現(xiàn),感興趣的可以了解一下2023-11-11
基于Python實(shí)現(xiàn)2種反轉(zhuǎn)鏈表方法代碼實(shí)例
這篇文章主要介紹了基于Python實(shí)現(xiàn)2種反轉(zhuǎn)鏈表方法代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
python?包實(shí)現(xiàn)JSON?輕量數(shù)據(jù)操作
這篇文章主要介紹了python?包實(shí)現(xiàn)JSON?輕量數(shù)據(jù)操作,文章介紹內(nèi)容首先將對(duì)象轉(zhuǎn)為json字符串展開主題詳細(xì)內(nèi)容需要的小伙伴可以參考一下2022-04-04
初步認(rèn)識(shí)Python中的列表與位運(yùn)算符
這篇文章主要介紹了Python中的列表與位運(yùn)算符,是Python入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-10-10
總結(jié)分析python數(shù)據(jù)化運(yùn)營(yíng)關(guān)聯(lián)規(guī)則
本文內(nèi)容主要介紹了python數(shù)據(jù)化運(yùn)營(yíng)中關(guān)聯(lián)規(guī)則的一般應(yīng)用場(chǎng)景,以及關(guān)聯(lián)規(guī)則的實(shí)現(xiàn),并例舉了適應(yīng)的應(yīng)用示例,方便大家更直觀的理解應(yīng)用2021-08-08
python通過(guò)線程實(shí)現(xiàn)定時(shí)器timer的方法
這篇文章主要介紹了python通過(guò)線程實(shí)現(xiàn)定時(shí)器timer的方法,涉及Python線程與定時(shí)器timer的使用技巧,需要的朋友可以參考下2015-03-03
Python使用FastAPI制作一個(gè)視頻流媒體平臺(tái)
在構(gòu)建視頻流媒體平臺(tái)時(shí),用戶認(rèn)證與視頻上傳是兩個(gè)至關(guān)重要的功能,FastAPI作為一個(gè)高效的Web框架,可以輕松處理這些需求,下面我們看看具體實(shí)現(xiàn)方法吧2025-04-04

