Huffman编码及其实现[Python]

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

香农范诺双飞翼,Huffman编码一点通_哔哩哔哩_bilibili

猜你喜欢

转载自blog.csdn.net/Blossomers/article/details/125801864