算法-哈夫曼树 编码
问题来源:对一段文字怎样编码能够在保证数据正确传输的前提下数据量最小
不等长编码相比等长编码在某些情况下能够解决上述条件,如何构造符合要求的不等长编码就是哈夫曼树需要解决的问题,此不等长编码就是哈夫曼编码
不等长编码相比等长编码在相同条件下能够节约编码字符,但是有下面两个问题需要解决
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)
浙公网安备 33010602011771号