数据结构和算法——Huffman树和Huffman编码

article/2025/9/29 0:51:43

Huffman树是一种特殊结构的二叉树,由Huffman树设计的二进制前缀编码,也称为Huffman编码在通信领域有着广泛的应用。在word2vec模型中,在构建层次Softmax的过程中,也使用到了Huffman树的知识。

在通信中,需要将传输的文字转换成二进制的字符串,假设传输的报文为:“AFTERDATAEARAREARTAREA”,现在需要对该报文进行编码。

一、Huffman树的基本概念

在二叉树中有一些基本的概念,对于如下所示的二叉树:

这里写图片描述

  • 路径

路径是指在一棵树中,从一个节点到另一个节点之间的分支构成的通路,如从节点8到节点1的路径如下图所示:

这里写图片描述

  • 路径长度

路径长度指的是路径上分支的数目,在上图中,路径长度为2。

  • 节点的权

节点的权指的是为树中的每一个节点赋予的一个非负的值,如上图中每一个节点中的值。

  • 节点的带权路径长度

节点的带权路径长度指的是从根节点到该节点之间的路径长度与该节点权的乘积:如对于1节点的带权路径长度为:2。

  • 树的带权路径长度

树的带权路径长度指的是所有叶子节点的带权路径长度之和。

有了如上的概念,对于Huffman树,其定义为:

给定 n 权值作为n个叶子节点,构造一棵二叉树,若这棵二叉树的带权路径长度达到最小,则称这样的二叉树为最优二叉树,也称为Huffman树。

由以上的定义可以知道,Huffman树是带权路径长度最小的二叉树,对于上面的二叉树,其构造完成的Huffman树为:

这里写图片描述

二、Huffman树的构建

由上述的Huffman树可知:节点的权越小,其离树的根节点越远。那么应该如何构建Huffman树呢?以上述报文为例,首先需要统计出每个字符出现的次数作为节点的权:

这里写图片描述

接下来构建Huffman树:

  • 重复以下的步骤:
    • 按照权值对每一个节点排序:D-F-T-E-R-A
    • 选择权值最小的两个节点,此处为D和F生成新的节点,节点的权重为这两个节点的权重之和,为2
  • 直到只剩最后的根节点

按照上述的步骤,该报文的Huffman树的生成过程为:

这里写图片描述

这里写图片描述

对于树中节点的结构为:

#define LEN 512
struct huffman_node{char c;int weight;char huffman_code[LEN];huffman_node * left;huffman_node * right;
};

对于Huffman树的构建过程为:

int huffman_tree_create(huffman_node *&root, map<char, int> &word){char line[MAX_LINE];vector<huffman_node *> huffman_tree_node;map<char, int>::iterator it_t;for (it_t = word.begin(); it_t != word.end(); it_t++){// 为每一个节点申请空间huffman_node *node = (huffman_node *)malloc(sizeof(huffman_node));node->c = it_t->first;node->weight = it_t->second;node->left = NULL;node->right = NULL;huffman_tree_node.push_back(node);}// 开始从叶节点开始构建Huffman树while (huffman_tree_node.size() > 0){// 按照weight升序排序sort(huffman_tree_node.begin(), huffman_tree_node.end(), sort_by_weight);// 取出前两个节点if (huffman_tree_node.size() == 1){// 只有一个根结点root = huffman_tree_node[0];huffman_tree_node.erase(huffman_tree_node.begin());}else{// 取出前两个huffman_node *node_1 = huffman_tree_node[0];huffman_node *node_2 = huffman_tree_node[1];// 删除huffman_tree_node.erase(huffman_tree_node.begin());huffman_tree_node.erase(huffman_tree_node.begin());// 生成新的节点huffman_node *node = (huffman_node *)malloc(sizeof(huffman_node));node->weight = node_1->weight + node_2->weight;(node_1->weight < node_2->weight)?(node->left=node_1,node->right=node_2):(node->left=node_2,node->right=node_1);huffman_tree_node.push_back(node);}}return 0;
}

其中,map结构的word为每一个字符出现的频率,是从文件中解析出来的,解析的代码为:

int read_file(FILE *fn, map<char, int> &word){if (fn == NULL) return 1;char line[MAX_LINE];while (fgets(line, 1024, fn)){fprintf(stderr, "%s\n", line);//解析,统计词频char *p = line;while (*p != '\0' && *p != '\n'){map<char, int>::iterator it = word.find(*p);if (it == word.end()){// 不存在,插入word.insert(make_pair(*p, 1));}else{it->second ++;}p ++;}}return 0;
}

当构建好Huffman树后,我们分别利用先序遍历和中序遍历去遍历Huffman树,先序遍历的代码为:

void print_huffman_pre(huffman_node *node){if (node != NULL){fprintf(stderr, "%c\t%d\n", node->c, node->weight);print_huffman_pre(node->left);print_huffman_pre(node->right);}
}

中序遍历的代码为:

void print_huffman_in(huffman_node *node){if (node != NULL){print_huffman_in(node->left);fprintf(stderr, "%c\t%d\n", node->c, node->weight);print_huffman_in(node->right);}
}

得到的结构与上图中的结构一致。

三、由Huffman树生成Huffman编码

有了上述的Huffman树的结构,现在我们需要利用Huffman树对每一个字符编码,该编码又称为Huffman编码,Huffman编码是一种前缀编码,即一个字符的编码不是另一个字符编码的前缀。在这里约定:

  • 将权值小的最为左节点,权值大的作为右节点
  • 左孩子编码为0,右孩子编码为1

因此,上述的编码形式如下图所示:

这里写图片描述

从上图中,E节点的编码为:00,同理,D节点的编码为1001

Huffman编码的实现过程为:

int get_huffman_code(huffman_node *&node){if (node == NULL) return 1;// 利用层次遍历,构造每一个节点huffman_node *p = node;queue<huffman_node *> q;q.push(p);while(q.size() > 0){p = q.front();q.pop();if (p->left != NULL){q.push(p->left);strcpy((p->left)->huffman_code, p->huffman_code);char *ptr = (p->left)->huffman_code;while (*ptr != '\0'){ptr ++;}*ptr = '0';}if (p->right != NULL){q.push(p->right);strcpy((p->right)->huffman_code, p->huffman_code);char *ptr = (p->right)->huffman_code;while (*ptr != '\0'){ptr ++;}*ptr = '1';}}return 0;
}

利用上述的代码,测试的主函数为:

int main(){// 读文件FILE *fn = fopen("huffman", "r");huffman_node *root = NULL;map<char, int> word;read_file(fn, word);huffman_tree_create(root, word);fclose(fn);fprintf(stderr, "pre-order:\n");print_huffman_pre(root);fprintf(stderr, "in-order:\n");print_huffman_in(root);get_huffman_code(root);fprintf(stderr, "the final result:\n");print_leaf(root);destory_huffman_tree(root);return 0;
}

print_leaf函数用于打印出每个叶节点的Huffman编码,其具体实现为:

void print_leaf(huffman_node *node){if (node != NULL){print_leaf(node->left);if (node->left == NULL && node->right == NULL) fprintf(stderr, "%c\t%s\n", node->c, node->huffman_code);print_leaf(node->right);}
}

destory_huffman_tree函数用于销毁Huffman树,其具体实现为:

void destory_huffman_tree(huffman_node *node){if (node != NULL){destory_huffman_tree(node->left);destory_huffman_tree(node->right);free(node);node = NULL;}
}

其最终的结果为:

这里写图片描述

参考文献

  • 《大话数据结构》
  • 《数据结构》(C语言版)

http://chatgpt.dhexx.cn/article/0qRA3PyY.shtml

相关文章

Huffman编码压缩文件

文章目录 前言一、Huffman编码是什么&#xff1f;二、Huffman编码的实现方法三、Huffman压缩文件1.统计文件个字符出现的次数2.生成Huffman树3.生成码表4.对文件进行压缩 四、Huffman解压文件五、实验结果总结 前言 这个实验是我在学习信息论与编码时所做的课程实验&#xff0…

自适应Huffman编码

自适应Huffman编码&#xff0c;可用初始编码表&#xff08;数字音视频技术&#xff0c;实验二&#xff09; 如果你已经理解了 自适应Huffman编码 &#xff0c;那么你不应该浪费时间在无聊的实验上 实验目的 1、深入掌握自适应Huffman编码的原理 2、掌握自适应Huffman编码算法…

huffman python,哈夫曼(Huffman)编码python代码实现

首先看定义 哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式&#xff0c;哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法&#xff0c;该方法完全依据字符出现概率来构造异字头的平均长度最短的码字&#xff0c;有时称…

Huffman Tree

Huffman Tree 哈夫曼树&#xff1b;哈夫曼编码&#xff1b;最优二叉树 自底向上 变长编码&#xff1b;前缀编码&#xff1b;熵编码 数据无损压缩&#xff1b;最短编码&#xff1b;最佳判定树 一、基本概念 Huffman Tree&#xff0c;又称最优二叉树&#xff0c;是带权路径长度最…

Huffman Codes

题目 In 1953, David A. Huffman published his paper “A Method for the Construction of Minimum-Redundancy Codes”,and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encounte…

HuffmanTree

#include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "string.h"typedef int ELEMTYPE;//哈弗曼树节点结构体 typedef struct HuffmanTree {ELEMTYPE weight;ELEMTYPE id;//区分权值相同的节点struct HuffmanTree* …

JPEG中Huffman解码实例讲解

DHT Huffuman表格式 -------------------------------------------------------------------------- 名称 字节数 值 说明 -------------------------------------------------------------------------- 段标识 1 FF 段类型 1 C4 段…

哈夫曼树(huffman)

学完了huffman树&#xff0c;讲一下自己对它的理解 huffman树遵循二叉树的原则&#xff0c;每个节点最多有两个子节点&#xff0c;但是每个节点都带有一个权重&#xff0c;如果我们要将一组字符串 “ B D C A F E ” 插入huffman树&#xff0c;每个字符都会带有一个权重&#…

Huffman树和Huffman编码

文章目录 Huffman树的定义带权路径长度WPL Huffman树的构造Huffman树的特点 Huffman编码构造Huffman编码 Huffman树的定义 哈夫曼&#xff08;Huffman&#xff09;树&#xff0c;又称最优二叉树&#xff0c;是一类带权路径长度WPL最短的树。 带权路径长度WPL 要理解带权路径…

Huffman树(哈夫曼树)

哈夫曼树又称最优二叉树&#xff0c;是一种带权路径长度最短的二叉树。所谓树的带权路径长度&#xff0c;就是树中所有的叶结点的权值乘上其到根结点的路径长度&#xff08;若根结点为0层&#xff0c;叶结点到根结点的路径长度为叶结点的层数&#xff09;。树的带权路径长度记为…

虚拟机下安装BackTrack5 (BT5)教程及BT5汉化

isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuid50397 isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuserisare PS&#xff1a;back track 安装过程中有2点要注意&#xff1a;第一&#xff1a;复制到99%的时候会等大约10来分钟&a…

bt 下载工具 deluge 配置 优化 使用

目录 Ubuntu 18 配置 deluge Deluge 安卓远程客户端 Deluge 性能调优 deluge是基于libtorrentpython的跨平台bt/pt客户端&#xff0c;适合在Linux环境下使用 deluge完全开源免费&#xff0c;对IPv6支持良好&#xff0c;性能优于transmission&#xff1b;在嵌入式设备上使用d…

BT5的U盘完整安装

BT5是什么就不用多说了&#xff0c;从网上看了许多教程&#xff0c;大多是利用unetbootin工具将ISO文件直接解压到U盘上&#xff0c;这样并不能完全使用BT&#xff0c;保存好的文件&#xff0c;重启机器后就没了&#xff0c;其实就是当做光盘使用了&#xff0c;另外还有一个方法…

有哪些好用的BT下载器?

​​​​​​2022年5个好用的 BT/ 磁力链接下载工具推荐 &#xff5c;Windows 、安卓系统 | 科技雷达 A full-featured download manager

BT是如何下载的

BT协议简介 一、BT下载是怎么来的&#xff1f; 在互联网上下载文件的方式大概有这么几种&#xff1a;FTP、HTTP、BT、eMule(电驴)等&#xff0c; 浏览器会直接支持FTP和HTTP下载&#xff0c;BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别&…

ed2k下载

ed2k下载 在下载ed2k资源的时候&#xff0c;浏览器一般不能直接下载&#xff0c;这个时候该怎么办呢&#xff1f; 方法一&#xff1a;下载迅雷&#xff0c;直接安装 方法二&#xff1a;使用在线工具&#xff0c;将链接转化为别的形式 https://tool.lu/urlconvert/ 方法三&am…

BT是怎么下载的

BT协议简介 一、BT下载是怎么来的? 在互联网上下载文件的方式大概有这么几种:FTP、HTTP、BT、eMule(电驴)等, 浏览器会直接支持FTP和HTTP下载,BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别: FTP 是 File Transfer Protocol(文件…

最好用的bt下载器qbittorrent下载安装使用教程

qBittorrent绝对是我心目中BT下载工具中的NO.1&#xff0c;虽说我平时也会用迅雷下载国内的某些资源&#xff0c;但是仍然不妨碍它是我心目中的主力下载神器&#xff01;它可以说是我最早接触的除迅雷之外的一款BT下载神器。它是完全免费的种子和磁力链接下载工具&#xff0c;最…

BT5 WIFI破解

实验环境 VMwareWorkstation 9.0 BackTrack5 R3-GNOME-32 工具说明 VMware&#xff1a;著名的虚拟机软件&#xff0c;本实验采用虚拟机环境下安装BackTrack。 BackTrack&#xff1a;是一个基于Ubuntu GNU/Linux的发行版本&#xff0c;主要用做数字取证和入侵测试。其无线安全审…

BT5下载地址

http://www.backtrack-linux.org/downloads/ 下载方法&#xff1a; 1,先填写好网页里的三个框,如: Your Name(你的名字): ABC Email Address(邮箱): ABC163.com Country(国家): china 2,然后点"download" 3,按照自己的…