一、基本原理
1、huffman编码原理
huffman编码是一种无失真编码方式,是可变长(VLC)编码的一种。
huffman编码基于信源的概率统计模型,基本思路是出现概率大的信源符号编长码,出现概率小的符号编短码,从而使平均码长最小。
2、数据结构
在本实验中的数据结构中,用到了两个数据结构:
在程序实现过程中,使用了一种二叉树的数据结构,由它编出的码是即时码。树是一种重要的非线性数据结构,直观的看,它是数据元素(在树中称为结点)按分支关系组织起来的结构。在计算机科学中,二叉树是每个结点最多有两个字树的有叙树,常用来实现查找或排序。
二叉树的两个子树有左右之分,次序不能颠倒,二叉树的第i层至多有2^(i-1)个结点;深度(二叉树的层数)为k的二叉树至多有2^(k)-1个结点。
树的表示方法有许多,最常用的是:(a(b(c,d),e(d,e(……));(先将根结点放入一对圆括号中,然后把它的子树由左至右的顺序放入括号中,同层子树之间用逗号隔开。
树的遍历是对二叉树的一种最基本的操作,通过访问二叉树的所有节点,将二叉树转换为一个线性序列。
3、对内存数据编解码
待添加。(本实验未涉及)
二、流程分析
1、项目框架
本实验由两个项目组成:huff_code(静态库)和huff_run(win32控制台项目)
静态库的配置(方法一:):huff_code是一个静态库,不能直接运行,在vs中点生成->生成解决方案,在debug文件夹下找到huff_code.lib文件,连同huffman.h拷贝至huff_run文件项目文件夹下,在huff_run的main函数之前添加#include<huff_code.lib>和#include<huffman.h>.以及#pragma comment(lib,"huff_code.lib")//这是告诉编译器在编译形成的.obj件和.exe文件中加一条信息,使得 链接器在链接库的时候要去找wsock32.lib这个库,不要先去找别的库。
方法二:在debug文件夹下找到huff_code.lib文件,连同huffman.h拷贝至huff_run文件项目文件夹下,在huff_run的main函数之前添加#include<huff_code.lib>,设置huff_run的项目属性,在vc++目录的包含目录里添加huffman.h的所在的路径,库目录里加入huff_code.lib所在的路径,在连接器->输入->附加依赖项->输入“huff_code.h”。
2、程序框架
2.1编码流程
(1)将文件以ASCII字符流的形式读入,统计每个符号发生的概率
(2)将文件中所有出现过的字符概率从小到大进行排列
(3)每一次选出最小的两个值,作为二叉树的两个叶子节点,将他们的和作为根节点,这两个叶子节点不再参与比较,新的根节点参与比较
(4)重复三,直到得出和为1的根节点
(5)将形成额二叉树的左节点标1,右节点标0,把从最上面的根节点到最下面的叶子节点途中遇到的0、1序列串起来就得到了各个字符的编码表示。
2.2解码流程
(1)读取码表并重建huffman树
(2)读取huffman码字,并解码输出
三、关键代码分析
1、头文件
int huffman_encode_file(FILE *in, FILE *out,FILE *out_Table);//step1: changed by yzhang for huffman statistics
int huffman_decode_file(FILE *in, FILE *out);
int huffman_encode_memory(const unsigned char *bufin,
unsigned int bufinlen,
unsigned char **pbufout,
unsigned int *pbufoutlen);
int huffman_decode_memory(const unsigned char *bufin,
unsigned int bufinlen,
unsigned char **bufout,
unsigned int *pbufoutlen);
通过调用四个函数完成对输入文件以及内存里文件的编、解码工作。在huffman_encoder_file的函数接口里添加FILE *outTable,用来输出编码的相关信息。
2、主函数(huffcode.c->)
int main(int argc, char** argv)
{
char memory = 0;//0表示不对内存数据操作,1表示对内存数据操作
char compress = 1;//压缩编码为1,解压缩为0
int opt;
const char *file_in = NULL, *file_out = NULL;
//step1:add by yzhang for huffman statistics
const char *file_out_table = NULL;
//end by yzhang
FILE *in = stdin;
FILE *out = stdout;
//step1:add by yzhang for huffman statistics
FILE * outTable = NULL;
//end by yzhang
/* Get the command line arguments. */
while((opt = getopt(argc, argv, "i:o:cdhvmt:")) != -1)//读命令行参数选项,argc和argv代表代表参数个数和内容,参数 optstring为选项字符串, 告知 getopt()可以处理哪个选项以及哪个选项需要参数,
//如果选项字符串里的字母后接着冒号":",则表示还有相关的参数,全域变量optarg 即会指向此额外参数。
{
printf("opt:%c ",opt);
switch(opt)
{
case 'i'://输入文件,有相关参数
file_in = optarg;
break;
case 'o'://输出文件,有相关参数
file_out = optarg;
break;
case 'c'://编码
compress = 1;
break;
case 'd'://解码
compress = 0;
break;
case 'h'://输出帮助信息
usage(stdout);
return 0;
case 'v'://输出版本信息
version(stdout);
return 0;
case 'm'://对内存编码或解码
memory = 1;
break;
// by yzhang for huffman statistics
case 't'://输出编解码信息表格
file_out_table = optarg;//
break;
//end by yzhang
default:
usage(stderr);
return 1;
}
}