本节主要介绍了哈夫曼树的由来、构造哈夫曼树的步骤以及图解、以及如何过渡到一个哈夫曼编码。
class HTNode:
def __init__(self,d=" ",w=None):
self.data=d
self.weight=w
self.parent=-1
self.lchild=-1
self.rchild=-1
self.flag=True#标记是左孩子结点还是右孩子结点
def CreateHT():
global ht,n0,D,W#ht是这些结点的存储空间,n0是叶子结点的个数,D是存储各个结点值的列表,W是存储各个结点权重的列表
ht=[None]*(2*n0-1)#分配结点的存储空间
heap=[]#优先队列(小根堆)符合本情形,建立一个优先队列,每个元素为[w,i],按照w的权值建立小根堆
#先为每一个叶子结点输入进ht
for i in range(n0):
ht[i]=HTNode(D[i],W[i])
heapq.headppush(heap.[W[i],i])#因为只对权值进行每一次的排序操作,所以只让权值和索引进优先队列
for i in range(n0,2*n0-1):#逐个添加每一个结点最终形成一个二叉树
# 有限队列(小根堆)每一次进元素都会重新排序,保证按权值排列
#出优先队列中最小的两个结点形成新结点
p1=heapq.headpop(head)
p2=heapq.headpop(head)
#建一个空结点用来存储
ht[i]=HTNode()
ht[i].weight=ht[p1[1]].weight+ht[p2[1]].weight#上面规定了每一个结点有两个属性,p1[1]就代表着这个结点的索引
ht[p1[1]].parent=i#更新正在操作的处于下面处于左边的结点的parent指针
ht[i].lchild=p1[1]#正在生成结点的左孩子域设置为处于左下方的结点
ht[p1[1]].flag=True#标记它位于左边
ht[p2[1]].parent=i#同理对处于右下方的结点操作
ht[i].rchild=p2[1]#正在生成结点的右孩子域设置为处于右下方的结点
ht[p2[1]].flag=False#标记它处于右边
heapq.heappush(head.[ht[i].weight,i])#把更新好的结点进入优先队列
def CreateHCode():
global n0#n0是叶子结点个数
global ht#ht是存放结点的列表
global hcd#是存放全局哈夫曼编码的列表
hcd=[]
#下面代码是从下往上去找到根节点
for i in range(n0):
code=[]#存放ht[i]结点的哈夫曼编码
j=i
while ht[j].parent!=-1:
if ht[j].flag:#如果走的这条是左,则标记为0
code.append("0")
else:#如果走的是右,则标记为1
code.append("1")
j=ht[j].parent#继续回到上一层进行while循环
code.reverse()#最后反过来
hcd.append(''.join(code))#把这个哈夫曼编码加入到hcd列表中