python 规范霍夫曼编码

        霍夫曼编码是一种无损数据压缩算法,其中数据中的每个字符都分配有可变长度的前缀代码。出现频率最低的字符获得最大代码,出现频率最高的字符获得最小代码。使用这种技术对数据进行编码非常简单且高效。但是,解码使用此技术生成的比特流效率低下。解码器(或解压缩器)需要了解所使用的编码机制,以便将编码数据解码回原始字符。 

        因此,需要将编码过程的信息与编码数据一起作为字符表及其对应代码传递给解码器。在对大量数据进行常规霍夫曼编码时,此表会占用大量内存空间,而且如果数据中存在大量唯一字符,则由于存在代码本,压缩(或编码)数据大小会增加。因此,为了使解码过程在计算上高效,同时仍保持良好的压缩率,引入了规范霍夫曼码。 

        在标准霍夫曼编码中,使用为每个符号生成的标准霍夫曼代码的位长。首先根据符号的位长按非递减顺序对符号进行排序,然后根据每个位长按字典顺序对符号进行排序。第一个符号获得一个全为零且长度与原始位长相同的代码。对于后续符号,如果符号的位长等于前一个符号的位长,则将前一个符号的代码加一并分配给当前符号。 

        否则,如果符号的位长大于前一个符号的位长,则在增加前一个符号的代码后,将零附加到该代码上,直到长度等于当前符号的位长,然后将代码分配给当前符号。 
此过程继续处理其余符号。 

以下示例说明了该过程:

考虑以下数据: 

特点频率
A10
b1
C15
d7

生成的标准霍夫曼码的位长度为:  

特点霍夫曼编码位长度
A112
b1003
C01
d1013
  • 步骤 1:根据位长对数据进行排序,然后根据每个位长度按字典顺序对符号进行排序。 
特点位长度
C1
A2
b3
d3
  • 步骤 2:为第一个符号的代码分配与位长相同数量的“0”。 
    ‘c’的代码:0
    下一个符号‘a’的位长为 2 > 前一个符号‘c’的位长为 1。将前一个符号的代码增加 1 并附加 (2-1)=1 个零并将代码分配给‘a’。 
    ‘a’的代码:10
    下一个符号‘b’的位长为 3 > 前一个符号‘a’的位长为 2。将前一个符号的代码增加 1 并附加 (3-2)=1 个零并将代码分配给‘b’。 
    ‘b’的代码:110
    下一个符号‘d’的位长为 3 = 前一个符号‘b’的位长为 3。将前一个符号的代码增加 1 并将其分配给‘d’。 
    ‘d’的代码:111
  • 步骤3:最终结果。  
特点规范霍夫曼编码
C0
A10
b110
d111

        该方法的基本优点是,传递给解码器的编码信息可以更紧凑、更节省内存。例如,可以简单地将字符或符号的位长度传递给解码器。由于长度是连续的,因此可以轻松根据长度生成规范代码。 
有关使用 Huffman 树生成 Huffman 代码的信息,请参阅之前的文章如下:

c语言:c语言 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪c语言-CSDN博客

c++:c++ 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪算法设计核心代码-CSDN博客

c#:C# 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

c++ STL:c++ STL 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

java:java 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

python:python 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

javascript:JavaScript 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

方法:一种简单有效的方法是为数据生成一棵哈夫曼树,并使用类似于 Java 中的 TreeMap 的数据结构来存储符号和位长,以使信息始终保持排序。然后可以使用增量和按位左移运算来获取规范代码。 

执行:

import heapq
from collections import defaultdict

# Node class to store data and its frequency
class Node:
    def __init__(self, char, freq):
        self.char = char
        self.freq = freq
        self.left = None
        self.right = None

    # Defining comparators less_than and equals
    def __lt__(self, other):
        return self.freq < other.freq

    def __eq__(self, other):
        if(other == None):
            return False
        if(not isinstance(other, Node)):
            return False
        return self.freq == other.freq

# Function to generate Huffman codes
def code_gen(root, code_length, code_map):
    if root is None:
        return

    if root.left is None and root.right is None:
        code_map[len(code_length)].append(root.char)

    code_gen(root.left, code_length + '0', code_map)
    code_gen(root.right, code_length + '1', code_map)

# Main function implementing Huffman coding
def testCanonicalHC(chararr, freq):
    # Priority queue to store heap tree
    q = [Node(chararr[i], freq[i]) for i in range(len(chararr))]
    heapq.heapify(q)

    while len(q) > 1:
        left = heapq.heappop(q)
        right = heapq.heappop(q)

        merged = Node(None, left.freq + right.freq)
        merged.left = left
        merged.right = right

        heapq.heappush(q, merged)

    root = heapq.heappop(q)
    code_map = defaultdict(list)
    code_gen(root, "", code_map)

    # Generate Canonical Huffman codes
    canonical_map = {}
    c_code = 0
    for length in sorted(code_map.keys()):
        for char in sorted(code_map[length]):
            canonical_map[char] = bin(c_code)[2:].zfill(length)
            c_code += 1
        c_code <<= 1

    # Print Canonical Huffman codes
    for char in sorted(canonical_map, key=lambda x: (len(canonical_map[x]), x)):
        print(f"{char}: {canonical_map[char]}")

# Driver code
if __name__ == "__main__":
    chararr = ['a', 'b', 'c', 'd']
    freq = [10, 1, 15, 7]
    testCanonicalHC(chararr, freq)

输出:
c:0
a:10
b:110
d:111   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值