贪心算法的高逼格应用——Huffman编码

简介: 贪心算法的高逼格应用——Huffman编码

Huffman编码

       在计算机的世界里,通常的编码方法有固定长度编码和不等长度编码两种。采用不等长度编码能使总码长度较短。

       Huffman编码利用字符的使用频率来编码,是不等长编码方法,它使得经常使用的字符编码较短,不常使用的字符编码较长。这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

       例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用Huffman编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节,即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

       除了使编码尽可能短,不等长编码还需解决另外一个问题,即不能有二义性,例如,ABCD四个字符如果编码如下:

   A:0

   B:1

   C:01

   D:10

那么现在有一列数0110,该怎样翻译呢? 是翻译为ABBA,ABD,CBA,还是CD? 那么如何消除二义性呢? 解决的办法是任何一个字符的编码不能是另一个字符编码的前缀,即前缀码特性。

       哈夫曼编码很好地解决了上述关键问题,被广泛应用于数据压缩,尤其是远距离通信和大容量数据存储方面。

算法详解

       Huffman编码的基本思想是以字符的使用频率作为权值构建一棵Huffman树,然后利用Huffman树对字符进行编码。构造一棵Huffman树,是将所要编码的字符作为叶子结点,该字符在文件中的使用频率作为叶子结点的权值,以自底向上的方式,通过n-1次的“合并”运算后构造出的一棵树,核心思想是权值越大的叶子离根越近。

回到本文题目,那贪心算法和Huffman编码有什么关系呢?

Huffman算法在构建Huffman树时采用的就是贪心策略,每次从树的集合中取出没有双亲且权值最小的两棵树作为左右子树,构造一棵新树,新树根节点的权值为其左右孩子结点权值之和,将新树插入到树的集合中,求解步骤如下。

(1) 确定合适的数据结构。编写程序前需要考虑的情况有:

● Huffman树是二叉树,树中没有度为1的结点,则一棵有n个叶子结点的Huffman树共有 2n-1 个结点 ( n-1 次的“合并”,每次产生一个新结点)。

● 构成Huffman树后,为求编码,需从叶子结点出发走一条从叶子到根的路径。

● 译码需要从根出发走一条从根到叶子的路径,那么我们需要知道每个结点的权值、双亲、左孩子、右孩子和结点的信息。

(2) 初始化。构造n棵结点为n个字符的单结点树集合 ,每棵树只有一个带权的根结点,权值为该字符的使用频率。

(3) 如果T中只剩下一棵树,则Huffman树构造成功,跳到步骤(6)。否则,从集合T中取出没有双亲且权值最小的两棵树 ,将它们合并成一棵新树 ,新树的左孩子为 ,右孩子为 的权值为 的权值之和。

(4) 从集合T中删去 ,加入 到集合T

(5) 重复以上(3)~(4)步。

(6) 约定左分支上的编码为“0”,右分支上的编码为“1”。从叶子结点到根结点逆向求出每个字符的Huffman编码,从根结点到叶子结点路径上的字符组成的字符串为该叶子结点的Huffman编码。算法结束。

构建Huffman树的过程图解如下

代码

说明

(1) 节点数组前n项是要进行编码的字符,后面n-1项是通过n-1次合并后产生的非叶子节点

(2) 由于节点数组前n项是要进行编码的字符,故通过Huffman树获得编码时,只需遍历节点数组前n项即可

节点数组初始如下:

import sys
 
 
# Huffman节点类
class HuffmanNode:
    def __init__(self, weight=0, parent=-1, left_child=-1, right_child=-1, value=""):
        # 权重
        self.weight = weight
        # 父节点索引
        self.parent = parent
        # 左孩子节点索引
        self.left_child = left_child
        # 右孩子节点索引
        self.right_child = right_child
        # 代表的字符
        self.value = value
 
    def __str__(self):
        return "weight:{}, parent:{}, left_child:{}, right_child:{}, value:{}".format(self.weight, self.parent, self.left_child, self.right_child, self.value)
 
 
# 构造Huffman树
def huffman_tree(nodes, num):
    # 需要构建的非叶子节点有N-1个,均排在节点数组后面,故须循环N-1次
    for i in range(num-1):
        # 最小的两个权值,这里m1小于等于m2
        m1 = m2 = sys.maxsize
        # 最小权值节点对应的索引
        x1 = x2 = -1
        # 循环当前所有可用的节点
        for j in range(num + i):
            if(nodes[j].weight < m1 and nodes[j].parent==-1):
                m2 = m1
                x2 = x1
                m1 = nodes[j].weight
                x1 = j
            elif(nodes[j].weight < m2 and nodes[j].parent==-1):
                m2 = nodes[j].weight
                x2 = j
        # 给需要合并成树的子节点设置父节点索引
        nodes[x1].parent = num + i
        nodes[x2].parent = num + i
        # 给合并成树的父节点设置子节点信息
        nodes[num + i].left_child = x1
        nodes[num + i].right_child = x2
        nodes[num + i].weight = m1 + m2
 
 
# 通过Huffman树获得Huffman编码
def huffman_code(nodes, num):
    # 最终结果
    huff_codes = dict()
    # 循环所有的叶子节点,叶子节点都在节点数组前面
    for i in range(num):
        # 该叶子节点对应的编码数组
        leaf_code = []
        # 当前节点索引
        c = i
        # 父节点索引
        p = nodes[i].parent
        while p != -1:
            # 当前节点是父节点的左孩子,编码为0,当前节点是父节点的右孩子,编码为1
            if nodes[p].left_child == c:
                leaf_code.insert(0, 0)
            elif nodes[p].right_child == c:
                leaf_code.insert(0, 1)
            # 将当前节点和父节点沿路径上移
            c = p
            p = nodes[c].parent
        
        if len(leaf_code)>0:
            huff_codes[nodes[i].value] = "".join(str(lc) for lc in leaf_code)
    return huff_codes
 
 
# 算法主体
def run():
    N = 6
    # 初始化节点数组,对N个元素进行编码,则Huffman树的节点数是2N-1
    nodes = [HuffmanNode() for _ in range(2*N - 1)]
    # 初始化叶子节点
    nodes[0].weight = 5
    nodes[0].value = "a"
    nodes[1].weight = 32
    nodes[1].value = "b"
    nodes[2].weight = 18
    nodes[2].value = "c"
    nodes[3].weight = 7
    nodes[3].value = "d"
    nodes[4].weight = 25
    nodes[4].value = "e"
    nodes[5].weight = 13
    nodes[5].value = "f"
    # 构建Huffman树 
    huffman_tree(nodes, N)
    # 从Huffman树中获得叶子节点的Huffman编码
    result = huffman_code(nodes, N)
    
    for r in result:
        print("{} 的 Huffman编码是:{}".format(r, result[r]))
 
 
if __name__ == "__main__":
    run()

程序运行结果如下

a 的 Huffman编码是:1000

b 的 Huffman编码是:11

c 的 Huffman编码是:00

d 的 Huffman编码是:1001

e 的 Huffman编码是:01

f 的 Huffman编码是:101

作者这水平有限,有不足之处欢迎留言指正

相关文章
|
8天前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
38 15
|
14天前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
8天前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
33 3
 算法系列之数据结构-Huffman树
|
2天前
|
人工智能 自然语言处理 供应链
从第十批算法备案通过名单中分析算法的属地占比、行业及应用情况
2025年3月12日,国家网信办公布第十批深度合成算法通过名单,共395款。主要分布在广东、北京、上海、浙江等地,占比超80%,涵盖智能对话、图像生成、文本生成等多行业。典型应用包括医疗、教育、金融等领域,如觅健医疗内容生成算法、匠邦AI智能生成合成算法等。服务角色以面向用户为主,技术趋势为多模态融合与垂直领域专业化。
|
9天前
|
存储 人工智能 算法
通过Milvus内置Sparse-BM25算法进行全文检索并将混合检索应用于RAG系统
阿里云向量检索服务Milvus 2.5版本在全文检索、关键词匹配以及混合检索(Hybrid Search)方面实现了显著的增强,在多模态检索、RAG等多场景中检索结果能够兼顾召回率与精确性。本文将详细介绍如何利用 Milvus 2.5 版本实现这些功能,并阐述其在RAG 应用的 Retrieve 阶段的最佳实践。
通过Milvus内置Sparse-BM25算法进行全文检索并将混合检索应用于RAG系统
|
16天前
|
存储 缓存 监控
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
29 3
|
26天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
49 12
|
24天前
|
算法 安全 网络安全
基于 Python 的布隆过滤器算法在内网行为管理中的应用探究
在复杂多变的网络环境中,内网行为管理至关重要。本文介绍布隆过滤器(Bloom Filter),一种高效的空间节省型概率数据结构,用于判断元素是否存在于集合中。通过多个哈希函数映射到位数组,实现快速访问控制。Python代码示例展示了如何构建和使用布隆过滤器,有效提升企业内网安全性和资源管理效率。
50 9
|
3天前
|
人工智能 自然语言处理 算法
从第九批深度合成备案通过公示名单分析算法备案属地、行业及应用领域占比
2024年12月20日,中央网信办公布第九批深度合成算法名单。分析显示,教育、智能对话、医疗健康和图像生成为核心应用领域。文本生成占比最高(57.56%),涵盖智能客服、法律咨询等;图像/视频生成次之(27.32%),应用于广告设计、影视制作等。北京、广东、浙江等地技术集中度高,多模态融合成未来重点。垂直行业如医疗、教育、金融加速引入AI,提升效率与用户体验。
|
16天前
|
算法 安全 Java
探讨组合加密算法在IM中的应用
本文深入分析了即时通信(IM)系统中所面临的各种安全问题,综合利用对称加密算法(DES算法)、公开密钥算法(RSA算法)和Hash算法(MD5)的优点,探讨组合加密算法在即时通信中的应用。
17 0

热门文章

最新文章