我有一个霍夫曼编码的最小堆代码,你可以在这里看到:http://rosettacode.org/wiki/Huffman_coding#Python
我正在尝试制作一个类似于min-heap的最大堆Shannon-Fano代码。
这是一段代码:
from collections import defaultdict, Counter
import heapq, math
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
heapq._siftup_max(heap, 0)
return returnitem
return lastelt
def _heappush_max(heap, item):
"""Push item onto heap, maintaining the heap invariant."""
heap.append(item)
heapq._siftdown_max(heap, 0, len(heap)-1)
def sf_encode(symb2freq):
heap = [[wt, [sym, ""]] for sym, wt in symb2freq.items()]
heapq._heapify_max(heap)
while len(heap) > 1:
lo = _heappop_max(heap)
hi = _heappop_max(heap)
for pair in lo[1:]:
pair[1] = '0' + pair[1]
for pair in hi[1:]:
pair[1] = '1' + pair[1]
_heappush_max(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
print heap
return sorted(_heappop_max(heap)[1:], key=lambda p: (len(p[1]), p))
但我有这样的输出:
Symbol Weight Shannon-Fano Code
! 1 1
3 1 01
: 1 001
J 1 0001
V 1 00001
z 1 000001
E 3 0000001
L 3 00000001
P 3 000000001
N 4 0000000001
O 4 00000000001
我是否正确使用heapq来实现Shannon-Fano编码?这个字符串中的问题:
_heappush_max(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
我不明白如何解决它。
期望输出类似于霍夫曼编码
Symbol Weight Huffman Code
2875 01
a 744 1001
e 1129 1110
h 606 0000
i 610 0001
n 617 0010
o 668 1000
t 842 1100
d 358 10100
l 326 00110
添加了:
好吧,我试过没有heapq这样做,但是有不可阻挡的递归:
def sf_encode(iA, iB, maxP):
global tupleList, total_sf
global mid
maxP = maxP/float(2)
sumP = 0
for i in range(iA, iB):
tup = tupleList[i]
if sumP < maxP or i == iA: # top group
sumP += tup[1]/float(total_sf)
tupleList[i] = (tup[0], tup[1], tup[2] + '0')
mid = i
else: # bottom group
tupleList[i] = (tup[0], tup[1], tup[2] + '1')
print tupleList
if mid - 1 > iA:
sf_encode(iA, mid - 1, maxP)
if iB - mid > 0:
sf_encode(mid, iB, maxP)
return tupleList
答案 0 :(得分:0)
在Shannon-Fano编码中,您需要以下steps:
Shannon-Fano树是根据设计的规范建造的 定义有效的代码表。实际的算法很简单:
- 对于给定的符号列表,请开发相应的列表 概率或频率计数使每个符号的相对性 发生的频率是已知的。
- 根据符号排列符号列表 频率,左边最常出现的符号 在右边最不常见。
- 将列表分为两部分, 左侧部分的总频率计数接近 尽可能合适的权利。
- 分配列表的左侧部分 二进制数字0,右边部分分配数字1.这 表示第一部分中符号的代码都将开始 0表示,第二部分的代码全部以1开头。
- 递归地将步骤3和4应用于两半中的每一半, 细分组并向代码添加位,直到每个符号具有 成为树上相应的代码叶。
醇>
所以你需要代码进行排序(你的输入看起来已经排序,所以你可以跳过这个),还有一个递归函数,它选择最好的分区,然后在列表的前半部分和后半部分进行递归。
对列表进行排序后,元素的顺序永远不会改变,因此不需要使用heapq来执行这种编码方式。