在这段代码中有不止一个奇怪之处;-),但我认为您的主要问题是:def __cmp__(self, a):
return cmp(self.code, a.code)
堆操作使用comparison方法对堆进行排序,但出于某种原因,您告诉它按当前代码长度对Node排序。几乎可以肯定的是,你想把他们的重量堆起来,对吗?哈夫曼编码就是这样工作的。在
^{pr2}$
对于其余的,很难理解,因为5个符号中有4个是相同的(4个0和1个1)。你怎么知道它是否有效?在
在循环内部,这是紧张的:lo, hi = sorted([heappop(tree), heappop(tree)])
考虑到对__cmp__的修复,这更简单:lo = heappop(tree)
hi = heappop(tree)
排序是没有意义的-总是弹出当前最小的元素。所以弹出两次,并且lo <= hi必须为真。在
我想多说些;-),但在这一点上,我对你最终要达到的目标感到困惑。如果您同意__cmp__应该被修复,那么进行更改并编辑问题,以使一些输入和输入都能得到您希望得到的确切输出。在
更多
关于:it gives the top nodes the longest codewords instead of the final leaves,
这不是一个“offby1”的事情,它更像是一个“向后”的事情;—)Huffman编码首先考虑权重最小的节点。节点从堆中弹出的时间越晚,权重越高,其代码的长度也应越短。但随着过程的进行,代码会变得更长。随着流程的进行,它们应该会变得越来越短。在
你不能在建树的时候这样做。事实上,在树构建过程完成之前,代码是不可知的。在
所以,我将给出一些工作代码,您可以根据自己的喜好进行修改,而不是猜测意图等。我将包括一个示例输入及其输出:from heapq import heappush, heappop, heapify
class Node(object):
def __init__(self, weight, left, right):
self.weight = weight
self.left = left
self.right = right
self.code = None
def __cmp__(self, a):
return cmp(self.weight, a.weight)
class Symbol(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
self.code = None
def __cmp__(self, a):
return cmp(self.weight, a.weight)
def encode(symbfreq):
# return pair (sym2object, tree), where
# sym2object is a dict mapping a symbol name to its Symbol object,
# and tree is the root of the Huffman tree
sym2object = {sym: Symbol(sym, w) for sym, w in symbfreq}
tree = sym2object.values()
heapify(tree)
while len(tree) > 1:
lo = heappop(tree)
hi = heappop(tree)
heappush(tree, Node(lo.weight + hi.weight, lo, hi))
tree = tree[0]
def assigncode(node, code):
node.code = code
if isinstance(node, Node):
assigncode(node.left, code + "0")
assigncode(node.right, code + "1")
assigncode(tree, "")
return sym2object, tree
i = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
s2o, t = encode(i)
for v in s2o.values():
print v.name, v.code
打印出:a 010
c 00
b 011
e 11
d 10
所以,正如我们所希望的那样,权重最高的符号拥有最短的代码。在