哈夫曼编码(Huffman Coding)是一种可变长的前缀码,可以有效地压缩数据:通常可以节省20%~90%的空间。哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码。
前缀码,没有任何码字是其他码字的前缀。
首先,获取字符与频率的关系。
其次,构建哈夫曼树。
最后,根据0=转向左孩子,1=转向右孩子,构建哈夫曼编码。
# Python 3: Huffman code class Node(object): def __init__(self, name: str = None, data=None): self.name: str = name self.data = data self.lchild: Node = None self.rchild: Node = None class HuffmanTree(object): # 根据Huffman树的思想:以叶子节点为基础,建立Huffman树 def __init__(self): self.nodes = [] # 根据输入的字符及其频数生成叶子节点 self.root = None self.codes = {} def build(self, char_weights): """ :param char_weights: e.g., char_weights = [('a', 7), ('b', 19), ('c', 2), ('d', 6), ('e', 32), ('f', 3), ('g', 21), ('h', 10)] """ self.nodes = [Node(part[0], part[1]) for part in char_weights] while len(self.nodes) > 1: # 结点列表根据频率倒序排列。 self.nodes.sort(key=lambda node: node.data, reverse=True) # 获取当前2个最小结点的值,并生成父结点。 temp_node = Node(data=(self.nodes[-1].data + self.nodes[-2].data)) # 将当前2个最小结点的值赋予父结点,最小结点是左结点,次最小结点是为右结点。 temp_node.lchild = self.nodes.pop(-1) temp_node.rchild = self.nodes.pop(-1) # 将该父结点投入到结点列表中。 self.nodes.append(temp_node) self.root = self.nodes[0] def traverse(self): self.__traverse(self.root) def __traverse(self, node): """ in-order traverse :param node: """ if node is None: return else: self.__traverse(node.lchild) print(node.data) self.__traverse(node.rchild) def generate_huffman_codes(self): self.__generate_huffman_codes(self.root, '0') def __generate_huffman_codes(self, node, code): if node is None: return else: if node.lchild is None and node.rchild is None and node.name is not None: self.codes[f'{node.name}({node.data})'] = code else: self.__generate_huffman_codes(node.lchild, code + '0') self.__generate_huffman_codes(node.rchild, code + '1') #huffman codes: #b(19)=000 #g(21)=001 #c(2)=010000 #f(3)=010001 #d(6)=01001 #a(7)=01010 #h(10)=01011 #e(32)=011