赫夫曼编码/译码器
l 摘要:
利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在 发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要有一个完整的编/译码系统。本文编写了一个简单的赫夫曼码的编/译码小程序。
本程序主要实现了利用赫夫曼二叉树对一篇英语文档进行编码,对得到的编码利用同一个二叉树解码,最后对解码得到的文档进行测试。经过测试后得出结论,赫夫曼编码虽然提高了信道的利用率,但在信号的保真度上不高,一旦信号出错,整个译码将出错。
l 实验目的:
理解Huffman二叉树的概念
学会使用Huffman编码对数据进行无损压缩的原理
一、问题描述:
利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在 发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要有一个完整的编/译码系统。本文编写了一个简单的赫夫曼码的编/译码小程序。
二、设计要求:
该程序有以下流程:
Initialization(初始化):从输入端输入标准字符集(initdata.dat)和待编码ASCII文件(data.dat),并统计和计算出文章中出现的字符频率,概率和字符数。并计算出信源熵H(entropy)。
EnCoding(编码过程):由输入端输入的各字符出现频率为权值构造赫夫曼二叉树。子叶便是文中出现的各字符。通过根到子叶的路径将其转换为赫夫曼编码。再将源文档中的字符替换为相应的赫夫曼码,并存档(code.dat)。
DeCoding(译码过程):在接收端接收到译码文件(code.dat)后,利用译码过程中生成的赫夫曼二叉树译码。对译码文件扫描,将赫夫曼码替换为原文档,结果存为文档(test.dat)。
Testing(测试):对原文件和译码文件进行校队,相同则编译成功,不相同则编译失败。
Print(打印代码文件):打印内存中的赫夫曼树。各字符对应的编码,编码平均长度,编码效率(信源熵/编码平均长度),显示原文本,编码文本和译码文本。
三、算法描述:
编码算法:
Input:w[],n//权值数组和数组的大小
Output:HT,HC//赫夫曼二叉树和赫夫曼编码表。
1.由输入的权值数组构造n个赋权的二叉树。
2.在这些二叉树中选取权值最小的两个构造一棵新的二叉树,并删除子叶。
3.如果只剩一棵二叉树,则赫夫曼二叉树构造完毕。否则在剩下的二叉树中返回第二步。
//---从子叶到个逆向求每个字符的赫夫曼编码------
1.从上面过程构造出的二叉树的第一个子叶开始,寻找它的双亲。
2.判断当前结点有无双亲,若无双亲,则全部出栈,并存入赫夫曼编码表吗,下一个子叶结点,转第一步。
3.判断当前结点是其双亲的左孩子还是右孩子,左孩子,则‘0’入栈,右孩子,则‘1’入栈。
译码算法:
Input:code.dat
Output:test.dat
从code文件的开始到结尾依次读取字符,通过读取到的字符从赫夫曼二叉树的根结点开始,‘0’当前结点换为左孩子,‘1’当前结点换为右孩子,
重复上述过程直到叶子结点,并输出叶子节点所代表的字符到test文件中。
测试算法:
Intput;test.dat,data.dat//译码文件和原文件
Output:true or false
分别比较两个文件中的字符是否一样,只有全部一样才返回true否则返回false
四、变量说明:
#define MAX_CHARS_NUM 57
#define MAX_ROW 100
#define MAX_COL 100
char chars[MAX_CHARS_NUM];//存储标准字符集
char article[MAX_ROW][MAX_COL];//存储待统计文章
int frequence[MAX_CHARS_NUM] = {0};//各字符出现的频度
int size = 0; //文章中出现过的字符数目
vector<char> appCh;//出现过的字符
vector<int> appFre;//出现过的字符的频率
vector<double> probty;//出现过的字符的概率
double entropy;//信源熵
//=====本变量说明包含在"Initialization.h"中=======
typedef struct
{
unsigned int weight;//权值
char info; //子叶所代表的字符信息
unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree; // 数组存储的Huffam树
typedef char **HuffmanCode; // 编码表
五、函数说明:
#include "Initialization.h"
过程一:
void initChars(ifstream &);
初始化标准字符集,从文件初始化
void initArt(ifstream &);
初始化文章
void statistic(char (*)[MAX_COL], char *);
统计字符频率
void fillApp(char *, int *);
初始化非零频率字符集
void calcuPro(vector<int> &, vector<double> &);
计算字符概率,信源概率
void calcuEnt(vector<double> &,double &);
计算信源熵
利用公式-∑p(xi)log2(p(xi))
void readAndFill();
第一个过程的封装函数
#include "EnCoding.h"
第二个过程--编码阶段
int min1(HuffmanTree ,int );
取最小值,辅助Select函数
void Select(HuffmanTree &,int ,int &,int &);
选取最小和次小值
void HuffmanCoding(HuffmanTree &, HuffmanCode &,vector<int> &, int );
编码函数
void documentCode(vector<string> &);
创建"code.dat"文件
#include "DeCoding.h"
第三个阶段--译码阶段