哈夫曼编码实现
构建哈夫曼树
- 哈夫曼树又称最优二叉树。
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、… 则哈夫曼树的构造规则为:
1.将w1、w2、… 看成是有n 棵树的森林(每棵树仅有一个结点);
2.在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
3.从森林中删除选取的两棵树,并将新树加入森林;
4.重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
哈夫曼编码
通过哈夫曼树来构成的编码称为哈夫曼编码(Huffman code)。
假设文本包含6个字符【a,b,c,d,e,f】
字符在文本中出现的次数为【9,12,6,3,5,15】
构建哈夫曼树如下:
代码实现
# 创建节点类
class Node:
def __init__(self, name, weight):
self.name = name # 节点名
self.weight = weight # 节点权重
self.left = None # 节点左孩子
self.right = None # 节点右孩子
self.father = None # 节点父节点
#判断是否是左孩子
def is_left_child(self):
return self.father.left == self
#创建最初的叶子节点
def create_prim_nodes(data_set, labels):
nodes = []
for i in range(len(labels)):
nodes.append( Node(labels[i],data_set[i]) )
return nodes
# 创建huffman树
def create_HF_tree(nodes):
tree_nodes = nodes.copy()
while len(tree_nodes) > 1: #只剩根节点时,退出循环
tree_nodes.sort(key=lambda node: node.weight) #升序排列
new_left = tree_nodes.pop(0)
new_right = tree_nodes.pop(0)
new_node = Node(None, (new_left.weight + new_right.weight))
new_node.left = new_left
new_node.right = new_right
new_left.father = new_right.father = new_node
tree_nodes.append(new_node)
tree_nodes[0].father = None #根节点父亲为None
return tree_nodes[0] #返回根节点
#获取huffman编码
def get_huffman_code(root, nodes):
codes = {}
for node in nodes:
code=''
name = node.name
while node.father != None:
if node.is_left_child():
code = '0' + code
else:
code = '1' + code
node = node.father
codes[name] = code
return codes
if __name__ == '__main__':
labels = ['a','b','c','d','e','f']
data_set = [9,12,6,3,5,15]
nodes = create_prim_nodes(data_set,labels) #创建初始叶子节点
root = create_HF_tree(nodes) #创建huffman树
codes = get_huffman_code(root, nodes) #获取huffman编码
for key in codes.keys():
print(key,': ',codes[key]) #打印huffman码
输出结果:
a 的编码为:00
b 的编码为:01
c 的编码为:100
d 的编码为:1010
e 的编码为:1011
f 的编码为:11