实验三 无损数据压缩编解码实验(Huffman编解码)

~每一步中很多代码的注释都是跟着上一句写的,可以把注释连起来看~

一、实验原理

1. Huffman编码步骤

  (1)统计各个符号(把文件的一个字节看成一个符号)在文件中出现的概率,按照出现概率从小到大排序。
  (2)每一次选出概率最小的两个符号作为二叉树的叶节点,合并两个叶节点的概率,合并后的节点作为它们的父节点,直至合并到根节点。
  (3)二叉树的左节点为0,右节点为1,从上到下由根节点到叶节点得到每个叶节点的编码。
  因此,将节点和码字的数据类型定义如下

typedef struct huffman_node_tag //节点数据类型
{
    unsigned char isLeaf; // 1 表示为叶节点,0 表示不是叶节点
    unsigned long count; //这个字节在文件中出现的次数
    struct huffman_node_tag *parent; //父节点指针
    union{
        struct{ //如果不是叶节点,这里为左右子节点指针
            struct huffman_node_tag *zero, *one;
        };
        unsigned char symbol; //如果是叶节点,这里为一个字节的8位二进制数值
    };
} huffman_node;
//————————————————————————————————————————————————————————
typedef struct huffman_code_tag //码字数据类型
{
    unsigned long numbits; //码字长度
    /* 码字,一个unsigned char可以保存8个比特位,
    因此码字的第1到第8比特由低到高保存在bits[0]中,第9比特到第16比特保存在bits[1]中,以此类推 */
    unsigned char *bits;
} huffman_code;

2. 静态链接库的使用

  本实验由两个项目组成,第一个项目为 Huffman 编码的具体实现,名为 huff_code,创建项目时选择的是静态库,生成一个 .lib 文件。第二个项目 huff_run 只需要包含这个库即可调用其中的编码函数,后面的其它实验也要用到这个库。项目属性需要配置库目录属性,也就是第一个项目生成文件的路径,和附加依赖性属性,也就是库的名称,如图 1 所示。由于代码中用到了字节序转换的函数 htonl、ntohl,附加依赖项还需包含 ws2_32.lib。

这里写图片描述
图 1 项目属性的设置

二、实验流程及代码分析

1. Huffman编码流程

Created with Raphaël 2.1.0 读入文件 第一次扫描文件, 统计各字节出现频率 建立Huffman树 将码表写入文件 第二次扫描文件, 对源文件编码输出
(1)读取文件
//--------huffcode.c--------
...
static void usage(FILE* out){ //命令行参数格式
    fputs("Usage: huffcode [-i<input file>] [-o<output file>] [-d|-c]\n" "..." , out);
}
//————————————————————————————————————————————————————————
int main(int argc, char** argv)
{
    char memory = 0; //memory表示是否对内存数据进行操作
    char compress = 1; //compress为1表示编码,0表示解码
    const char *file_in = NULL, *file_out = NULL;
    FILE *in = stdin, *out = stdout;
    while((opt = getopt(argc, argv, "i:o:cdhvm")) != -1){ //读取命令行参数的选项
        switch(opt){
        case 'i': file_in = optarg; break; // i 为输入文件
        case 'o': file_out = optarg; break; // o 为输出文件
        case 'c': compress = 1; break; // c 为压缩操作
        case 'd': compress = 0; break; // d 为解压缩操作
        case 'h': usage(stdout); system("pause"); return 0; // h 为输出参数用法说明
        case 'v': version(stdout); system("pause"); return 0; // v 为输出版本号信息
        case 'm': memory = 1; break; // m 为对内存数据进行编码
        default: usage(stderr); system(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值