算法 哈夫曼树 编码
问题来源:对一段文字怎样编码能够在保证数据正确传输的前提下数据量最小
不等长编码相比等长编码在某些情况下能够解决上述条件,如何构造符合要求的不等长编码就是哈夫曼树需要解决的问题,此不等长编码就是哈夫曼编码
不等长编码相比等长编码在相同条件下能够节约编码字符,但是有下面两个问题需要解决
1、使用频率高的字符编码尽可能短
2、编码不能有二义性,任何一个字符编码不能是另一个编码的前缀
哈夫曼树使用频率越高的节点距离根越近,编码越短。 每个字符都是叶子,没有孩子所以任意一个字符编码不可能是另外编码的前缀;即同一级兄弟节点的编码肯定不相同
通过上述两点哈夫曼编码巧妙的解决了不等长编码的两个约束条件
哈夫曼树创建规则
1、初始森林为带权值的根节点组成的森林
2、选出无双亲权值最小的两个节点
3、选出的两个节点为左右子树生成一个新树,父节点的权值为选出两个节点之和
4、新树加入森林,重复步骤2-4;直到森林中只有一棵树
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#存储哈夫曼表信息的列表,每个元素都是Node类型
huffList = []
huffCodeList = []
init_len = 0 #huff初始化完成以后的长度
#定义每个节点的信息
class Node(object):
def __init__(self, value, weight, parent, lchild, rchild):
self.vaule = value
self.weight = weight
self.parent = parent
self.lchild = lchild
self.rchild = rchild
def init_append_node(value="-1", weight=-1, parent=-1, lchild=-1, rchild=-1):
huffList.append(Node(value, weight, parent, lchild, rchild))
def init_huffList():
while True:
recv = input("请输入原始节点信息,值 权重以空格分开;如果全部结束请输入end")
if (recv.strip()).lower() == "end":
return 0
recvList = recv.split(" ")
value = str(recvList[0])
weight = int(recvList[1])
init_append_node(value=value, weight=weight)
#填写哈夫曼表主逻辑
def createHuffTable():
lenhuffList = len(huffList)
if lenhuffList <= 2:
return "the tree length less than 2"
"""
遍历列表,取出没有双亲的最小两个子树生成一个新子树,新子树加入huffList
"""
#取出huffList中起始两个无父节点的子树作为起始节点,权重小的索引记录为temp_index1,另外一个记录为temp_index_2
temp_index1 = None
temp_index2 = None
#取出前两个无双亲的节点,作为临时变量来和后面的对象进行比较,其中temp_index2权值大于temp_index1
for i in range(lenhuffList):
#判断本趟循环是否已经取到值了
if (temp_index1 is not None) and (temp_index2 is not None):
break
#判断选择的节点是否已经被操作过
elif huffList[i].parent != -1:
continue
elif temp_index1 is not None: #保证先给temp_index1先赋值,保证排序的稳定
temp_index2 = i
else:
temp_index1 = i
if huffList[temp_index2].weight < huffList[temp_index1].weight: #注意<和<=使用需要保证排序的稳定
temp_index1, temp_index2 = temp_index2, temp_index1
#取出权值最小且无双亲的两个节点下标,temp_index1<=temp_index2。使用两个变量取出两个最下肢
for j in range(temp_index2, lenhuffList):
if huffList[j].parent != -1:
continue
# 第二个需要大于等于,否则遗漏=最小值场景。
elif (huffList[j].weight < huffList[temp_index2].weight) and (huffList[j].weight >= huffList[temp_index1].weight):
temp_index2 = j
elif huffList[j].weight < huffList[temp_index1].weight:
temp_index1 = j
else:
continue
#使用权重最小无双亲节点构造新树,新树的根加入huffList
init_append_node(weight=(huffList[temp_index1].weight+huffList[temp_index2].weight), lchild=temp_index1, rchild=temp_index2)
#将取出的两个权重最小值双亲信息进行修改
huffList[temp_index1].parent = len(huffList)-1
huffList[temp_index2].parent = len(huffList)-1
"""
哈夫曼树表生成以后就可以根据表来生成对应编码了
1、遍历表找到无child的节点,找到此节点的父节点,判断此节点是对应父节点的左孩子还是右孩子,左孩子记录为0,右孩子记录为1
2、对于父节点重复步骤1,直到根节点;使用列表记录,每次insert[0]
"""
#初始化code存储表;循环调用code需要注意调用前清空此列表
temp_index_code = []
def huffCode(index):
if huffList[index].parent != -1:
if huffList[huffList[index].parent].lchild == index:
temp_index_code.insert(0, 0)
else:
temp_index_code.insert(0, 1)
huffCode(huffList[index].parent)
#n个叶子节点组成的二叉树一共有2n-1个节点,循环调用,直到huffList长度为2n-1则结束调用
def createHuffTable_main():
init_huffList()
init_len = len(huffList)
while len(huffList) < (2*init_len-1):
createHuffTable()
return huffList
if __name__ == "__main__":
createHuffTable_main()
# init_codeList()
huffCode(1)
print(temp_index_code)