信源编码的三种方式与实现

您所在的位置:网站首页 解压文件有几种 信源编码的三种方式与实现

信源编码的三种方式与实现

2024-03-08 16:54| 来源: 网络整理| 查看: 265

信源编码的三种方式与实现 一、本文概述二、编码原理1. 哈夫曼编码2. 算术编码3. LZ编码 三、算法设计思路1. 哈夫曼编码a. 设置功能结构体和函数b. 压缩文件初始化统计表频度读入文件并统计频度对统计表频度排序建立哈夫曼树进行编码写文件 c. 解压文件 2. 算数编码3. LZ-78编码a. 设计功能类b. 主程序调用测试c. 功能类函数实现1. 函数 lz_compress2. 函数 lz_decompress3. 函数 IfStringInDic 和 函数 FindPreString4. 优化 四、实验拓展与编码操作五、编码结果与性能分析1. 哈夫曼编码2. LZ-78编码3. 算数编码 六、问题总结与体会

一、本文概述

这是第一次在CSDN上写blog,想写很久了,一直因为忙耽搁了,放假了,打算整理一下这学期的一些代码和实验写blog。 本文主要根据我信息论课程的信源编码大作业报告所写,相关代码放在我的GitHub上,初次在CSDN发blog,小小紧张哈哈哈。

本文主要实现了哈夫曼编码,且性能较为优秀。另外还拓展实现了LZ编码和算数编码,并在将哈夫曼和LZ-78两种编码方式的cpp文件通过统一的main.cpp文件整合在一起,可以通过运行project来选择希望的编码方式对目标文件进行编码。

另外,本文的实验中,也出现了一些编译器的问题,例如Visual Studio下和Mac下存在着一定的优劣对比。

本文中给出了一些实现的部分代码,完整代码见GitHub: https://github.com/YZ-WANG/Three-methods-for-source-encoding

二、编码原理

本文的实验实现了三种编码方式:哈夫曼编码、LZ编码和算数编码。下面分析其各自基本原理。

1. 哈夫曼编码

哈夫曼编码是是一种可变长的分组编码,完全依据各字符出现的概率来构造码字。二进制的哈夫曼编码是基于二叉树的编码思想,所有可能的输入符号在哈夫曼树上对应为一个节点,结点的位置就是该符号的哈夫曼编码。为了构造出唯一可译码,这些节点都是哈夫曼树上的终极结点(即叶子结点),不再延伸,不会出现前缀码。具体编码方法如下:

将信源消息符号按其出现的概率大小依次排列为 p1≥p2≥…≥Pn;取两个概率最小的字母分别配以 0 和 1 两个码元,并将这两个概率相加作为一个新字母的概率,与未分配二进制符号的字母一起重新排队;对重排后的两个概率最小符号重复步骤2的过程;不断继续上述过程,直到最后两个符号配以 0 和 1 为止;从最后一级开始,向前返回得到各个信源符号所对应的码元序列,即为相应码字。

特别地,有时为了得到最短平均码长,尽量减少赋长码的信源符号,需要在编码前对信源符号作添加,使得信源的符号数量满足 M(N-1)+1,其中M为正整数,N为进制,这样在多次合并后就能充分利用短码,以便降低平均码长。

此外,哈夫曼编码方法所得到的码并非是唯一的,造成非唯一的原因如下:

每次对信源缩减时,赋予信源最后两个概率最小的符号,用0和1是可以任意的,所以可以得到不同的哈夫曼编码,但不会影响码字的长度。对信源进行缩减时,两个概率最小的符号合并后的概率与其他信源符号的概率相同时,这两者在缩减信源中进行概率排序,其位置放置次序可以是任意的,故会得到不同的哈夫曼码。此时将影响码字的长度,一般将合并的概率放在上面,这样可以得到较小的码方差。

哈夫曼编码的特点:

哈夫曼码的编码方法保证了概率大的符号对应于短码,概率小的符号对应于长码,充分利用了短码;而是缩减信源的最后二个码字总是最后一位不同,从而保证了哈夫曼码是即时码。

哈夫曼码的编码效率是非常高的,它可以单个信源符号编码或用L较小的信源序列编码,对编码器的设计来说也将简单得多。但是应当注意,要达到很高的效率仍然需要按长序列来计算,这样才能使平均码字长度降低。 哈夫曼编码的解码则在识别出一个个叶子结点后按照叶子结点对应的原信源符号译码。

哈夫曼编码虽然效率出众,但仍然存在一些分组码所具有但缺点。例如概率特性必须精确测定,以此来编织码表,若略有变化,还需要更换码表。故实际编码过程中需要对原始数据扫描两遍,第一遍用来统计原始数据中各字符出现的概率,创建码表存放起来,第二遍则依据码表在扫描的同时进行编码,才能传输信息。如果将这种编码放在网络通信中,两遍扫描会引起较大的时延;如果用于数据压缩,则会降低速度。因此,出现了自适应哈夫曼编码方法,其码表不是实现构造,而是随着编码的进行,不断动态构造、调整。

2. 算术编码

由于在使用分组码对信源单符号进行编码时,没有将符号间的相关性纳入考虑之中:若将m个符号合起来进行编码则会增加设备复杂度,且组间符号的相关性还是无法纳入考虑。这就使得信源编码的匹配原则不能充分满足,编码效率有所损失。

为了克服这种局限性,一种基于非分组码的编码方法——算数编码应运而生。编码的基本思路是:将需要编码的全部数据看成某一 L L L 长序列,所有可能出现的L长序列的概率映射到 [ 0 , 1 ] [0,1] [0,1] 的区间上,把 [ 0 , 1 ] [0,1] [0,1] 区间分成许多小段,每段长度等于某一序列的概率。再在段内取一个二进制小数用作码字,其长度可与该序列的概率匹配,达到高效率编码的目的。

算数编码实际的编译码过程比较复杂,但在性能上具有许多优点,特别是所需要的参数很少,不像哈夫曼编码那样需要一个很大的码表。从理论上说,只要已知信源符号集及其符号概率,算数编码的平均码长可以接近符号熵。

具体编码方法如下:

将文件以字节为单位读入,并将其分割成bit串形式计算文件中bit0和bit1的总数量和各自的概率对一定长度L的符号串进行编码,并将数据写入压缩后文件中从压缩文件中读入数据,并还原成长度为L的符号串输入至解压文件中 3. LZ编码

LZ编码是由以色列研究者齐夫和伦佩尔完全脱离哈夫曼码和算术编码的设计思路,设计出的一系列比哈夫曼编码更有效、比算术编码更快捷的通用压缩算法。将这些算法统称为LZ系列算法。LZ系列算法利用一种巧妙的方式将字典技术应用于通用数据压缩领域,而且,可以从理论上证明LZ系列算法同样可以逼近信息熵的极限。

实验采用的 LZ-78编码 的编码过程如下:

设信源符号集 A = a 1 , a 2 , … , a K A={a1,a2,…,aK} A=a1,a2,…,aK 共K个符号,设输入信源符号序列为 U = ( u 1 , u 2 , … … , u L ) U=(u1,u2,……,uL) U=(u1,u2,……,uL),编码是将此序列分成不同的段。分解是迭代进行的,在第i步,编码器从 s i s_i si​ - 1 短语后的第一个符号开始向后搜索在此之前从未出现过的最短短语 s i s_i si​,将短语 s i s_i si​ 添入字典第i段。由于 s i s_i si​ 是此时字典中最短的新短语,所以 s i s_i si​ 在去掉最后一个符号 x x x 后所得的前缀必定是字典中之前已经出现过的。若设此前缀是在第 j ( ; i ) j(;i) j(


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3