霍夫曼(Huffman)编码算法详解之C语言版

article/2025/9/24 16:48:03

一、Huffman编码

霍夫曼(Huffman)树是一类带权路径长度最短的二叉树树。Huffman树的一个非常重要的应用就是进行Huffman编码以得到0-1码流进行快速传输。
在电报收发等数据通讯中,常需要将传送的文字转换成由二进制字符0、1组成的字符串来传输。为了使收发的速度提高,就要求电文编码要尽可能地短。此外,要设计长短不等的编码,还必须保证任意字符的编码都不是另一个字符编码的前缀,目的是解决译码的二义性。
例如:假设有一电文“EABCBAEDBCEEEDCEBABC”,其中的字符集为C={A,B,C,D,E},各个字符出现的次数集为W={3, 5, 4, 2, 6}。
在这里插入图片描述
以字符集C作为叶子结点,次数集W作为结点的权值来构造 Huffman树,则得到如下的Huffman树:
在这里插入图片描述
其中树叶结点就是电文中的字符,树叶中的数字就是对应字符出现的次数。

规定Huffman树中左分支代表“0”,右分支代表“1” ,则得到如下的Huffman树:
在这里插入图片描述
从根结点到每个叶子结点所经历的路径分支上的“0”或“1”所组成的字符串,为该结点所对应的编码,称之为Huffman编码。
各个字符的Huffman编码结果如下:
在这里插入图片描述

由于每个字符都是叶子结点,不可能出现在根结点到其它字符结点的路径上,所以一个字符的Huffman编码不可能是另一个字符的Huffman编码的前缀。

二、Huffman编码算法

1.编码方式
根据出现频度(权值)Weight,对叶子结点的Huffman编码有两种方式:
1)从叶子结点到根逆向处理,求得每个叶子结点对应字符的Huffman编码。
2)从根结点开始遍历整棵二叉树,求得每个叶子结点对应字符的Huffman编码。
2.逆向编码算法
本文以逆向编码为例,给出Huffman编码的算法。
对于每个树叶结点,其Huffman编码算法如下:
Step 1:把树叶作为当前结点,并获取其序号(数组的下标)
Step 2:获取当前结点的双亲结点的序号
Step 3:判断当前结点是其双亲结点的左或者右子树,如果是左,则编码为’0’,否则为’1’
Step 4:如果双亲结点为树根,则结束当前树叶的编码;否则,更新当前结点序号为其双亲的序号,返回Step 2.
:因为是从树叶开始到树根的编码,因此在存储编码的时候是倒序存储,即把当前树叶编码的第一个字符存到数组的最后位置,然后向前依次存储。

三、Huffman编码之C程序

1.Huffman编码算法

/******************************************************************************************
函数:void Huff_coding( int WeightNum, HTNode *HT, int NodeNum, char **HC )
功能:对Huffman树的叶子结点进行编码。
说明:Huffman树的结点存储在结构体数组HT里,其中前面WeightNum个元素为叶子结点,存储给定信息的权值。
输入参数:WeightNum:权值的个数,也就是Huffman树上叶子结点的个数NodeNum:  Huffman树上全部结点的个数HT:       存储Huffman树上所有结点的信息,权、双亲编号、左孩子编号、右孩子编号
输出参数:HC:       存储树叶结点的Huffman编码,每个编码均为一个字符串
*******************************************************************************************/
void Huff_coding( int WeightNum, HTNode *HT, int NodeNum, char **HC )
{int  k, sp, p, fp;char *cd;cd = new char[ WeightNum + 1 ];    // 动态分配存储编码的工作空间cd[ WeightNum ] = '\0';            // 编码的结束标志for ( k = 1; k <= WeightNum; k++ ) // 逐个求字符的编码{sp = WeightNum;  //从叶子结点到根逆向求编码for( p = k, fp = HT[k].Parent;  fp != 0; p = fp, fp = HT[p].Parent )  {if  ( HT[fp].Lchild == p )cd[ --sp ] = '0';elsecd[ --sp ] = '1';}HC[k] = new char[ WeightNum - sp + 1 ]; //为第k个字符分配空间 strcpy( HC[k], &cd[sp] ) ;}delete[] cd ;
}

2.完整的测试代码

#include"stdio.h"
#include"string.h"
#define  MAX_NODE  200     //Max_Node>2n-1//存储Huffman树结点
typedef struct
{char Character; //信息字符int  Weight;    //权int  Parent;    //双亲结点编号int  Lchild;    //左孩子结点编号 int  Rchild;    //右孩子结点编号
} HTNode ;//创建一棵叶子结点数为WeightNum的Huffman树,生成Huffman树后,树的根结点的下标是2WeightNum-1
void Create_Huffman( int WeightNum, HTNode *HT, int NodeNum );
//对已经创建的huffman树进行编码
void Huff_coding( int WeightNum, HTNode *HT, int NodeNum, char **HC );int main()
{int       WeightNum;//已知的权值的个数,也就是叶子结点个数int       NodeNum;  //huffman树上全部结点个数HTNode    *HT;      //存储Huffman树的结点char      **HC;     //存储Huffman编码WeightNum = 5;NodeNum   = 2 * WeightNum - 1;//建立Huffman树HT = new HTNode[MAX_NODE];Create_Huffman( WeightNum, HT, NodeNum );//向屏幕输出Huffman树的结点printf( "Huffman树上的结点:\n" );int i;for( i = 1; i <= NodeNum; i++ ){if( i <= WeightNum )printf( "%c %d %d %d %d\n", HT[i].Character, HT[i].Weight, HT[i].Parent, HT[i].Lchild, HT[i].Rchild );elseprintf( "%c %d %d %d %d\n", ' ', HT[i].Weight, HT[i].Parent, HT[i].Lchild, HT[i].Rchild );}//Huffman编码HC = new char*[ WeightNum + 1];Huff_coding( WeightNum, HT, NodeNum, HC );//向屏幕输出Huffman编码printf( "Huffman编码:\n" );for( i = 1; i <= WeightNum; i++ ){printf( "%c: %s\n", HT[i].Character, HC[i] );}delete[] HT;delete[] HC;return 0;
}
/******************************************************************************************
函数:void Create_Huffman( int WeightNum, HTNode *HT, int NodeNum )
功能:对给定的权值,生成Huffman树
说明:Huffman树的结点存储在结构体数组HT里,其中前面WeightNum个元素为叶子结点,存储给定信息的权值。
输入参数:WeightNum:权值的个数,也就是Huffman树上叶子结点的个数NodeNum:  Huffman树上全部结点的个数
输出参数:HT:       存储Huffman树上所有结点的信息,权、双亲编号、左孩子编号、右孩子编号
*******************************************************************************************/
void Create_Huffman( int WeightNum, HTNode *HT, int NodeNum )
{   int  k , j;   //循环下标int  w1, w2;  //w1 , w2分别保存权值最小的两个权值     int  p1, p2;  //p1 , p2保存两个最小权值的下标 for ( k = 1;  k <= NodeNum;  k++ )  //step1:初始化向量HT,即所有成员均当做树根{   if( k <= WeightNum ) //输入时,所有叶子结点都有权值{ printf( "Please Input Character : Character =?" );scanf( "%c", &HT[k].Character );   printf( "Please Input Weight : Weight =?" );scanf( "%d", &HT[k].Weight );     getchar(); //过滤输入数据时的换行符}  else  HT[k].Weight = 0;  //非叶子结点没有权值HT[k].Parent = HT[k].Lchild = HT[k].Rchild = 0 ;}for( k = WeightNum + 1; k <= NodeNum; k++ )//step2:对非叶子节点赋值,以生成H树{ p1 = 0;p2 = 0;w1 = 0xFFFFFFF;w2 = w1;for( j = 1 ; j <= k-1 ; j++)  //找到权值最小的两个值及其下标{if( HT[j].Parent == 0 )    //尚未合并 {if( HT[j].Weight < w1 ){w2 = w1; p2 = p1;w1 = HT[j].Weight;   p1 = j;  }else if( HT[j].Weight < w2 ){w2 = HT[j].Weight;  p2 = j;   }}      } HT[k].Lchild  = p1;    HT[k].Rchild  = p2;HT[k].Weight  = w1 + w2;HT[p1].Parent = k; HT[p2].Parent = k; }
}
/******************************************************************************************
函数:void Huff_coding( int WeightNum, HTNode *HT, int NodeNum, char **HC )
功能:对Huffman树的叶子结点进行编码。
说明:Huffman树的结点存储在结构体数组HT里,其中前面WeightNum个元素为叶子结点,存储给定信息的权值。
输入参数:WeightNum:权值的个数,也就是Huffman树上叶子结点的个数NodeNum:  Huffman树上全部结点的个数HT:       存储Huffman树上所有结点的信息,权、双亲编号、左孩子编号、右孩子编号
输出参数:HC:       存储树叶结点的Huffman编码,每个编码均为一个字符串
*******************************************************************************************/
void Huff_coding( int WeightNum, HTNode *HT, int NodeNum, char **HC )
{int  k, sp, p, fp;char *cd;cd = new char[ WeightNum + 1 ];    // 动态分配存储编码的工作空间cd[ WeightNum ] = '\0';            // 编码的结束标志for ( k = 1; k <= WeightNum; k++ ) // 逐个求字符的编码{sp = WeightNum;  //从叶子结点到根逆向求编码for( p = k, fp = HT[k].Parent;  fp != 0; p = fp, fp = HT[p].Parent )  {if  ( HT[fp].Lchild == p )cd[ --sp ] = '0';elsecd[ --sp ] = '1';}HC[k] = new char[ WeightNum - sp + 1 ]; //为第k个字符分配空间 strcpy( HC[k], &cd[sp] ) ;}delete[] cd ;
}

3.测试结果
在这里插入图片描述


http://chatgpt.dhexx.cn/article/jKFiY9gg.shtml

相关文章

哈夫曼编码

哈夫曼编码 概念前缀码的二叉树及权值哈夫曼编码的设计思想 实例伪代码 概念 哈夫曼编码是一种字符编码方式&#xff0c;是可变长编码的一种&#xff0c;1952年提出&#xff0c;依据字符在文件中出现的频率来建立一个用0,1串表示各字符&#xff0c;使平均每个字符的码长最短的…

图像处理—霍夫曼编码

图像压缩编码是专门研究图像数据压缩的技术&#xff0c;就是尽量减少表示数据图像所需要的数据量。 本章主要介绍图像压缩编码的基础知识&#xff0c;重点讲解常用的图像压缩编码方法&#xff0c;如霍夫曼编码、香农编码、算术编码、行程编码和预测编码及编码方法的MATLAB实现&…

哈夫曼编码(理解)

基础理解 什么是哈夫曼树&#xff08;Huffman Tree&#xff09; 给定N个带权值的叶子节点&#xff0c;如何构造出一个带权路径最小的二叉树&#xff1f; 在数据结构理论中&#xff0c;哈夫曼树又称为最优树&#xff0c;相关的知识点还有哈弗曼编码等。在正式介绍哈夫曼树之前…

学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!

CSDN 的学弟学妹们&#xff0c;大家好&#xff0c;我是沉默王二。 今天来给大家普及一下霍夫曼编码&#xff08;Huffman Coding&#xff09;&#xff0c;一种用于无损数据压缩的熵编码算法&#xff0c;由美国计算机科学家大卫霍夫曼在 1952 年提出——这么专业的解释&#xff…

哈夫曼编码详解

一&#xff1a;基本介绍 哈夫曼编码也翻译为 赫夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式, 属于一种程序算法 赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。 赫夫曼编码广泛地用于数据文件压缩。其压缩率通常在20%&#xff5…

赫夫曼编码

一 基本介绍 1 赫夫曼编码也翻译为哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式, 属于一种程序算法。 2 赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。 3 赫夫曼编码广泛地用于数据文件压缩。 其压缩率通常在20%&#xff5e;9…

哈夫曼编码(Huffman Coding)原理详解

哈夫曼编码 哈夫曼编码&#xff0c;又称为哈夫曼编码&#xff08;Huffman Coding&#xff09; 是一种可变长编码&#xff08; VLC, variable length coding)&#xff09;方式&#xff0c;比起定长编码的 ASCII 编码来说&#xff0c;哈夫曼编码能节省很多的空间&#xff0c;因…

霍夫曼编码详解

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;information-theory】&#xff0c;需要的朋友们自取。或者公众号【AIShareLab】回复 信息论 也可获取。 文章目录 霍夫曼编码最佳…

霍夫曼编码(Huffman Coding)

霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种。 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用…

Typecho 博客美化

以前用typecho博客&#xff0c;现在学生服务器到期了&#xff0c;先记录到csdn上&#xff0c;以后工作有钱了&#xff0c;再租个服务器写博客:) 代码高亮 https://www.typechodev.com/plugin/482.html 天气功能 使用心知天气带的插件就可以轻松实现了。 https://www.seniverse…

Hexo博客之博客美化

https://lqgjava.github.io/2019/08/24/Hexo博客之博客美化/ 只需阅读这一篇文章&#xff0c;就可以让你的博客变得丰富多彩&#xff0c;有添加卡通人物&#xff0c;添加鼠标点击爱心&#xff0c;添加鼠标指针样式 添加彩色滚动变换、添加背景音乐、添加动态彩带等&#xff0…

CSDN博客美化

排列博客分类 管理博客-分类专栏下修改 双击分类名称&#xff0c;即可编辑&#xff0c;输入“#”“空格”“分类名称”可将一级分类改成二级分类。 显示的效果 分类图标设置 编辑-设置图标&#xff0c;可以这里找阿里素材库 效果图

【CSDN】CSDN博客美化教程

一、效果 二、MarkDown简明教程 MarkDown简明教程 三、摘要 添加摘要&#xff0c;增加可读性。 PS. 其实&#xff0c;可以根据深度学习算法&#xff0c;自动生成摘要。 四、自定义博客栏目 五、修改皮肤

博客美化作业详细教程

博客美化作业 第一步 下载作业资源 第二步 在文件夹内打开下载资源 单击后缀为HTML文件的网页文件&#xff0c;右击用编译器打开 这些软件都可以&#xff08;除了紫色的&#xff09; 第三步 准备工作 首先让我们重新看下作业要求&#xff1a; 必须使用“类选择器”来美化网…

【全网最全的博客美化系列教程】04.访客量统计的实现

全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网…

Hexo博客美化之——IP签名图一网打尽

love421个人博客地址&#xff1a;https://www.makedreamsir.xyz IP签名图可以实时显示来访者的坐标&#xff0c;IP地址&#xff0c;操作系统&#xff0c;浏览器等等。 使用方法&#xff1a;将下面生成的链接插入到合适的位置即可。 项目原地址&#xff1a;点我打开 原作者博…

Web前端:博客美化:一、模板美化

1、选用模板simplememory 2、写css放在 这些会覆盖掉原来的css样式 我是在网上找的css代码二次加工的 : &#xff09; /*1、针对simplememory的修改*/ #google_ad_c1, #google_ad_c2 {display:none;} .syntaxhighlighter a, .syntaxhighlighter div, .syntaxhighlighter code, …

Hexo博客之主题美化

据说 NexT 是使用最多的Hexo主题,原因当然是比较漂亮啦!这个项目托管于github上,你可以fork一下,贡献代码。NexT官网上面给出了详细的主题配置过程,这里只是我的博客使用的一些配置以及NexT网站上配置中需要补充的部分。如果你是从头开始配置,请参考NexT官网。这篇文章介…

csdn写博客美化代码显示

本人写博客只是随笔记录&#xff0c;并不是很正规&#xff0c;见谅。 最近在写博客的时候发现自己贴的代码块就只显示代码&#xff0c;而一些前辈的代码块是这样的&#xff1a; 上图只看格式&#xff0c;代码无实际意义。 下面是我的代码块&#xff1a; 我写的代码块就…

【学习之博客美化】matery主题

为了方便我们这里使用 "Visual Studio Code"打开文件 将博客改为中文 目录&#xff1a;E:\IsQiyaBlog 将 " _config.yml " 文件中代码段 language: en 改为 language: zh-CN 修改主题菜单栏 将它们填上内容 新建分类 categories 页&#xff1a; hexo …