【数据结构】霍夫曼树

server/2024/9/25 2:53:45/

1.概念

霍夫曼树(Huffman Tree),又称最优二叉树,是一种带权路径长度最短的二叉树。在霍夫曼树中,叶子节点的权值通常代表字符出现的频率,非叶子节点的权值是其子节点权值的和。霍夫曼树广泛应用于数据压缩,尤其是霍夫曼编码,它是一种基于字符出现频率的变长前缀编码。

霍夫曼树的构建过程如下:

  1. 权值集合:首先,将给定的字符和它们对应的权值(频率)放入一个集合中。

  2. 选择最小的权值:每次从集合中选出两个具有最小权值的节点,将它们合并成一个新节点,新节点的权值是这两个子节点权值的和。

  3. 删除并添加:将选出的两个最小权值节点从集合中删除,并将新创建的节点添加到集合中。

  4. 重复步骤2和3:重复步骤2和3,直到集合中只剩下一个节点,这个节点就是霍夫曼树的根节点。

  5. 构建完成:此时,霍夫曼树构建完成,每个原始节点都成为了叶子节点,而新创建的节点都是非叶子节点。

霍夫曼编码的过程如下:

  1. 为每个叶子节点分配码字:从根节点开始,向左的路径分配0,向右的路径分配1。这样,每个叶子节点都会得到一个唯一的二进制编码。

  2. 构建编码表:将每个字符和它对应的霍夫曼编码放入一个编码表中。

  3. 编码:使用编码表对原始数据进行编码,替换每个字符为其对应的霍夫曼编码。

  4. 解码:解码时,从霍夫曼树的根节点开始,根据编码的0和1向左或向右移动。每次到达一个叶子节点,就输出对应的字符,然后从根节点开始继续解码过程。

霍夫曼编码是一种前缀编码,即任何一个字符的编码都不是另一个字符编码的前缀,这样可以保证编码的唯一可解性。由于频率高的字符分配的编码较短,频率低的字符分配的编码较长,因此霍夫曼编码能够实现数据的压缩。

2.如何自己实现霍夫曼编码?

实现霍夫曼编码需要定义数据结构来表示霍夫曼树节点,以及实现构建霍夫曼树和编码的过程。以下是一个简单的 C 语言实现。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义霍夫曼树节点结构
typedef struct {char ch;                // 字符(仅用于叶子节点)int freq;               // 字符频率char code[100];         // 霍夫曼编码struct HuffmanNode *left, *right; // 左右子树指针
} HuffmanNode;// 函数声明
HuffmanNode* createNode(int freq, char ch);
void printCodes(HuffmanNode* root, char* arr, int top);
void buildHuffmanTree(char ch[], int freq[], int size);
void destroyTree(HuffmanNode* root);int main() {int n, i;printf("请输入字符的数量:");scanf("%d", &n);char ch[n];int freq[n];printf("请输入字符及其频率(例如:a 5):\n");for(i = 0; i < n; i++) {scanf(" %c %d", &ch[i], &freq[i]);}buildHuffmanTree(ch, freq, n);return 0;
}// 创建一个新的霍夫曼树节点
HuffmanNode* createNode(int freq, char ch) {HuffmanNode* newNode = (HuffmanNode*)malloc(sizeof(HuffmanNode));newNode->ch = ch;newNode->freq = freq;newNode->left = newNode->right = NULL;strcpy(newNode->code, "");return newNode;
}// 打印霍夫曼编码
void printCodes(HuffmanNode* root, char* arr, int top) {if (root->left) {arr[top] = '0';printCodes(root->left, arr, top + 1);}if (root->right) {arr[top] = '1';printCodes(root->right, arr, top + 1);}if (!root->left && !root->right) {printf("%c: %s\n", root->ch, root->code);strcpy(root->code, arr);}
}// 构建霍夫曼树
void buildHuffmanTree(char ch[], int freq[], int size) {HuffmanNode *left, *right, *top;// 创建一个节点数组HuffmanNode* nodes[size];for(int i = 0; i < size; i++) {nodes[i] = createNode(freq[i], ch[i]);}// 构建霍夫曼树for(int i = 0; i < size - 1; i++) {// 找到两个最小频率的节点HuffmanNode* min1 = NULL, *min2 = NULL;for(int j = 0; j < size; j++) {if(nodes[j] && (!min1 || nodes[j]->freq < min1->freq)) {min2 = min1;min1 = nodes[j];} else if(nodes[j] && (!min2 || nodes[j]->freq < min2->freq)) {min2 = nodes[j];}}// 创建一个新的内部节点top = createNode(min1->freq + min2->freq, '\0');top->left = min1;top->right = min2;// 从节点数组中移除已合并的节点nodes[size + i] = top;nodes[min1 - nodes] = NULL;nodes[min2 - nodes] = NULL;}// 打印霍夫曼编码char arr[100];printCodes(nodes[size + size - 2], arr, 0);// 释放内存for(int i = 0; i < size; i++) {destroyTree(nodes[i]);}
}// 销毁霍夫曼树
void destroyTree(HuffmanNode* root) {if(root) {destroyTree(root->left);destroyTree(root->right);free(root);}
}

这段代码定义了霍夫曼树节点的结构,并提供了一个简单的命令行界面来输入字符及其频率。然后,它构建了霍夫曼树并打印了每个字符的霍夫曼编码。最后,它释放了分配给霍夫曼树的内存。

请注意,这个实现是为了演示目的而简化的。在实际应用中,霍夫曼编码的构建和解析通常更复杂,需要处理更多的边缘情况和优化。

以上就是霍夫曼树的基本使用,本次代码分享到此结束,后续还会更新数据结构算法的知识。最后的最后,还请大家点点赞,点点关注,谢谢大家!


http://www.ppmy.cn/server/14604.html

相关文章

js修改路由参数+vue——js基础

最近在写看板&#xff0c;要求执行某个操作后更改路由参数&#xff0c;方便用户保存地址以便于下次直接获取对应的数据。 比如&#xff1a;原地址&#xff1a;http://localhost:4200/tvType/out 执行某个操作后&#xff0c;地址变更为&#xff1a;http://localhost:4200/tvTyp…

全国各省市建设工程类专业职称评审要求总结(欢迎补充完善、沟通交流)

全国各省市建设工程类专业职称评审要求汇总统计如下&#xff0c;总体来说北京最难&#xff0c;经济欠发达、偏远地区评审要求相对简单&#xff0c;每个地方的要求存在一定的相似性&#xff0c;但又都各具特色&#xff0c;基本上来说论文是评审的必备条件&#xff0c;但是各个地…

npm详解:Node.js的包管理器

npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理器&#xff0c;它允许您安装、更新、删除和发布Node.js软件包。npm是Node.js生态系统中非常重要的组成部分&#xff0c;它使得开发人员能够轻松共享和重用代码&#xff0c;从而提高了开发效率和代码质量。 在…

JavaWeb过滤器

Javaweb过滤器是一种用于在Servlet处理请求之前或之后对请求进行预处理或后处理的组件。过滤器可以用于拦截请求、修改请求参数、过滤响应内容等操作。其主要作用包括&#xff1a; 拦截请求&#xff1a;过滤器可以拦截客户端请求&#xff0c;对请求进行验证、过滤或修改&#x…

中颖51芯片学习8. ADC模数转换

中颖51芯片学习8. ADC模数转换 一、ADC工作原理简介1. 概念2. ADC实现方式3. 基准电压 二、中颖芯片ADC功能介绍1. 中颖芯片ADC特性2. ADC触发源&#xff08;1&#xff09;**软件触发**&#xff08;2&#xff09;**TIMER4定时器触发**&#xff08;3&#xff09;**外部中断2触发…

PyCharm 无法运行的解决方案

问题&#xff1a; PyCharm 无法运行&#xff0c;该怎么办&#xff1f; 解决方案&#xff1a; 1. 检查 Python 解释器 确保已为 PyCharm 配置正确的 Python 解释器。打开 PyCharm&#xff0c;转到“文件”>“设置”>“项目”>“Python 解释器”。选择所需的 Python …

轻质砖隔墙温州中墙建材砂加气砼砌块文成泰顺乐清轻质砖隔墙安装B06A5.0鹿城龙湾瓯海加气块洞头瑞安龙港永嘉平阳苍南

轻质砖隔墙温州中墙建材砂加气砼砌块文成泰顺乐清轻质砖隔墙安装B06A5.0鹿城龙湾瓯海加气块洞头瑞安龙港永嘉平阳苍南 轻质砖隔墙是一种常用的非承重墙体材料&#xff0c;它主要由水泥、矿渣粉、河砂等材料制成&#xff0c;具有多孔结构&#xff0c;质量轻&#xff0c;易于加工…

03-JAVA设计模式-策略模式

策略模式 什么是策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是行为设计模式之一&#xff0c;它使你能在运行时改变对象的行为。在策略模式中&#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。 在策略模式中&#xff0c;…