数据结构课程设计

哈夫曼编码器

第1章 绪论

人们在使用计算机进行文件处理和传输的过程中,经常会使用到“压缩”这个概念,以节省存储空间,减少网络数据传输的压力,加快文件的传输速度,我们都会优先考虑将文件压缩打包后再进行传输。特别是网络视频资源,基本都是具备庞大的数据信息,如何实现文件的无损压缩,具有相当的现实意义。这也是多媒体信息处理领域的一个研究方向,经过不断的革新发展,如今,已经拥有强大的无损压缩编码技术。但是,如果追根溯源,计算机研究人员总是会提到美国数学家哈夫曼( David Huffman)于1952年发明的哈夫曼编码,是它拉开了数字编码技术的篇章。哈夫曼编码( Huffman Code)就是数据压缩技术中的一种无损压缩方法。
系统开发的背景为了提高信道利用率,缩短信息传输时间,降低传输成本,且在信息发送端通过个编码系统对待传数据预先编码,在信息接收端将传来的数据进行译码(复原),因此设计哈夫曼编码/译码器系统。
1951年,哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的二进制编码。由于无法证明哪个已有编码是最有效的,哈夫曼放弃对已有编码的研究,转向新的探索,最终发现了基于有序频率二叉树编码的想法,并很快证明了这个方法是最有效的。由于这个算法,学生终于青出于蓝,超过了他那曾经和信息论创立者香农共同研究过类似编码的导师。哈夫曼使用自底向上的方法构建二叉树,避免了次优算法Shannon-Fano编码的最大弊端──自顶向下构建树。
1952年,David A. Huffman在麻省理工攻读博士时发表了《一种构建极小多余编码的方法》(A Method for the Construction of Minimum-Redundancy Codes)一文,它一般就叫做Huffman编码。
Huffman在1952年根据香农(Shannon)在1948年和范若(Fano)在1949年阐述的这种编码思想提出了一种不定长编码的方法,也称霍夫曼(Huffman)编码。霍夫曼编码的基本方法是先对图像数据扫描一遍,计算出各种像素出现的概率,按概率的大小指定不同长度的唯一码字,由此得到一张该图像的霍夫曼码表。编码后的图像数据记录的是每个像素的码字,而码字与实际像素值的对应关系记录在码表中。
赫夫曼编码是可变字长编码(VLC)的一种。 Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就称Huffman编码。下面引证一个定理,该定理保证了按字符出现概率分配码长,可使平均码长最短。

第2章 系统需求分析

2.1 设计工具介绍

本编译器本人给简单的设计为四个模块,分别是:输入字符和权值并建立哈夫曼树(包括结点i,权值,字符,双亲,左孩子,右孩子),根据哈夫曼树內容进行编码、根据输入数值打印出哈夫曼树以及退出功能。

2.2 需求分析

人们在使用计算机进行文件处理和传输的过程中,经常会使用到“压缩”这个概念,以节省存储空间,减少网络数据传输的压力,加快文件的传输速度,我们都会优先考虑将文件压缩打包后再进行传输。特别是网络视频资源,基本都是具备庞大的数据信息,如何实现文件的无损压缩,具有相当的现实意义。这也是多媒体信息处理领域的一个研究方向,经过不断的革新发展,如今,已经拥有强大的无损压缩编码技术。但是,如果追根溯源,计算机研究人员总是会提到美国数学家哈夫曼( David Huffman)于1952年发明的哈夫曼编码,是它拉开了数字编码技术的篇章。哈夫曼编码( Huffman Code)就是数据压缩技术中的一种无损压缩方法。
在传送电文时,人们总是希望传送时间尽可能短,这就是要求使电文代码长度尽可能短。利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统能够对待传输数据预先编码,在接收端将传来的数据进行译码。对于双工信道(即可以双向传输信息的信道),每段都需要一一个完整的编/译系统。所以为这样的信息收发站写一个哈夫曼的编译码系统。

在这里插入图片描述

设某信源产生有五种符号u1、u2、u3、u4和u5,对应概率P1=0.4,P2=0.1,P3=P4=0.2,P5=0.1。首先,将符号按照概率由大到小排队,如图所示。编码时,从最小概率的两个符号开始,可选其中一个支路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止。从图(a)和(b)可以看出,两者虽平均码长相等,但同一符号可以有不同的码长,即编码方法并不唯一,其原因是两支路概率合并后重新排队时,可能出现几个支路概率相等,造成排队方法不唯一。一般,若将新合并后的支路排到等概率的最上支路,将有利于缩短码长方差,且编出的码更接近于等长码。这里图(a)的编码比(b)好。
赫夫曼码的码字(各符号的代码)是异前置码字,即任一码字不会是另一码字的前面部分,这使各码字可以连在一起传送,中间不需另加隔离符号,只要传送时不出错,收端仍可分离各个码字,不致混淆。
实际应用中,除采用定时清洗以消除误差扩散和采用缓冲存储以解决速率匹配以外,主要问题是解决小符号集合的统计匹配,例如黑(1)、白(0)传真信源的统计匹配,采用0和1不同长度游程组成扩大的符号集合信源。游程,指相同码元的长度(如二进码中连续的一串0或一串1的长度或个数)。按照CCITT标准,需要统计2×1728种游程(长度),这样,实现时的存储量太大。事实上长游程的概率很小,故CCITT还规定:若l表示游程长度,则l=64q+r。其中q称主码,r为基码。编码时,不小于64的游程长度由主码和基码组成。而当l为64的整数倍时,只用主码的代码,已不存在基码的代码。
长游程的主码和基码均用赫夫曼规则进行编码,这称为修正赫夫曼码,其结果有表可查。该方法已广泛应用于文件传真机中。

第3章 系统详细设计

本课程设计主要功能是:
(1)初始化:键盘输入N个字符和N个权值(根据设计要求中给出的字符和频度选取),建立哈夫曼树;
(2)编码:利用建好的哈夫曼树生成哈夫曼编码;
(3)输出编码;
(4)输出译码;
(5)退出;
构造哈夫曼树的方法如下: 初始化:每个字符就是一-个结点,字符的频度就是结点的权: 1.将结点按频度从小到大排序: 2、选取频度最小的两个结点,以它们为儿子,构造出一个新的结点:新结点的权值就是它两个儿子的权值之和;构造之后,从原来的结点序列里删除刚才选出的那两个结点,但同时将新生成的结点加进去; 3、如果结点序列里只剩下一一个结点,表示构造完毕,退出。否则回到第-一步。 编码: 上面已经生成了树,接着就该对该树进行编码了。 可以假定,对某个结点而言,其左孩子在当前阶段的编码为0,右孩子的编 码为1.这样就可以通过“树的遍历”的方式来生成字符一编码对照表。 来到这里,基本上艰苦的已经完成了,对某个具体的字符串编码和解码就只 是简单的“查表一替换" 的工作了。 译码:
译码也是个简单的查表–替换过程。如果利用该种编码发送字符串,则它的“字符一编码”对应表 也必须发送过去,不然对方是不知道怎么解码的。对给出的一串编码,从左向右,将编码组合起来并查表,“一旦”找到有匹配的字符,则马上将当前的编码替换为对应的字符。因为该编码是不会出现"某-一个字符的编码是另一个字符编码的缀”这种情况的,也就是不会出现类似于“A 00 B 0010” 这样 的情况,所以译码出来的字符串是唯一-的,而且就是原来进行编码的那一个。

经过分析,确定本系统结构图如下图所示:

在这里插入图片描述
图3.1哈夫曼编译器系统结构模型

3.1初始化

从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并显示出它的结点i,权值,字符,双亲,左孩子,右孩子。
哈夫曼树的定义

typedef struct{
   

char letter;//存储字符
int weight;//存储字符的权值
Int parent;/父亲
int lchild;/左孩子
int chilo;/右孩子
} HTNode, *HuffmanTree
 

在这里插入图片描述
图3.1.1

3.2 编码操作

利用以建好的哈夫曼树,对文件的正文进行编码,数值小的在左边,大的在右边,左边记为0,右边记为1,然后将结果输出在屏幕上。

//本结构存储哈夫曼树、编码等,便于后面的操作进行
typedef struct
{
   
HuffmanTree hT
动态分配数组存储哈夫曼编码表
HuffmanCode Hc
//记录输入字符的长度,编码用到
int len
char*c;//存储输入的字符
} Huf

在这里插入图片描述
图3. 2

3.3译码操作

在这里插入图片描述
图3. 3

3.4主函数

void main()
{
   
根据不同的选择,执行特定的函数,完成操作
}

第4章 系统实现

4.1 系统数据类型

根据系统所管理数据信息的要求和特点,将学生成绩信息定义成以下结构体类型:

struct HNode {
   int weight; int parent; int LChild; int RChild;
}

4.2 主函数

该函数中首先调用登录函数login(),用来显示用户的登录界面,要求输入用户密码,当密码正确时进入主菜单,根据用户选择的菜单项调用相应函数,实现相应的功能。当密码错误时退出主函数。主函数的源码如下:
void menu()
{
   
	cout << "=================================================" << endl;
	cout << "|****************哈夫曼树编码器*****************|" << endl;
	cout << "|                1.创建哈夫曼树                 |" << endl;
	cout << "|                2.哈夫曼编码                   |" << endl;
	cout << "|                3.哈夫曼译码                   |" << endl;
	cout << "|                4.退出                         |" << endl;
	cout << "=================================================" << endl
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值