Huffman编码是信源编码的一种,与香农压缩编码一样,都是为了压缩码率,即:用较短的码长去表征信源内的信息。
其思路大致可以描述为:给信源内,出现次数越多的事件,编以较短的码字,次数越少,编以较长的码字。大体思路与香农编码类似,但是不同的是香农是自顶向下去构建完全二叉树的【即每次都把事件组 依概率进行近似等分,以此来构建树】;Huffman是自下向上,从最优子树开始构建【即每次都找最小概率的两个事件作为子节点,合成父节点概率后再将这个概率放回事件组中 继续找最小概率的事件】
Huffman编码的实现主要可以分为两步:构建Huffman树+遍历节点编码【我的思路是分成两步做……】
其中Huffman树构建,有一步比较重要的是重置<号,也就是def __lt__(self,other)这个方法,他的作用是一旦出现了对于类实例的<比较,就调用这个方法,比如我在这里设计的是比较两个实例的值属性大小。此部分理解出自于stackoverflow:
python - Unable to understand __lt__ method - Stack Overflow
总体上来说 Huffman树构建用到了完全二叉树以及优先队列,编码我用的是类似于PCM编码里的层编码+层内编码的思路,逐层遍历树的结点,去编码。
from heapq import heapify,heappop,heappush
import heapq
class TreeNodes():
def __init__(self,val,lchild=None,rchild=None): # 构造函数参数设置为None,就可以在构造时先不用提供,等到先构造完毕后再用语句提供
self.val = val
self.lchild = lchild
self.rchild = rchild
def __lt__(self,other):
return self.val < other.val # change the '<' function if used on those objects:just compare the val between the two object
def Huffman_Tree(arr):
heapq.heapify(arr)
arrNode = [TreeNodes(val) for val in arr]
while len(arrNode) > 1:
min1 = heapq.heappop(arrNode)
min2 = heapq.heappop(arrNode)
# print(min1.val,min2.val)
newNode = TreeNodes(val=min1.val+min2.val,lchild = min1,rchild=min2)
heapq.heappush(arrNode,newNode)
return arrNode
arr = [0.07,0.13,0.22,0.01,0.57]
arrNode = Huffman_Tree(arr)
root = arrNode[0]
def recurseTreeNode(Node):
if Node == None:
return
print(Node.val)
recurseTreeNode(Node.lchild)
recurseTreeNode(Node.rchild)
# recurseTreeNode(root)
def encoder(root):
if root is None:
return
myqueue = []
myqueue.append(root)
turn = 1
realTurn = 0
dict = {}
while len(myqueue) !=0 :
node = myqueue.pop(0)
flag = 0 if turn % 2 == 0 else 1 # flag每轮交替 用来编写[层内编码]
realTurn += 1 if turn % 2 == 0 else 0 # 用来编[层编码]的位数
layerCode = str(flag)*realTurn
if node.lchild is not None:
layerInCode = '0'
huffmanCode = layerCode + layerInCode
dict[node.lchild.val] = huffmanCode
myqueue.append(node.lchild)
# 把val作为键 把encode作为值 后面再提取子集
if node.rchild is not None:
myqueue.append(node.rchild)
layerInCode = '1'
huffmanCode = layerCode + layerInCode
dict[node.rchild.val] = huffmanCode
# 把val作为键 把encode作为值 后面再提取子集
turn += 1
return dict
dict = encoder(root)
arrDict = {}
for key,value in dict.items():
if key in arr:
arrDict[key] = value
print(arrDict)
Result:
Reference:
Building Collision Simulations: An Introduction to Computer Graphics - YouTube