一.实验原理

1.Huffman编码的步骤:

(1)首先将所有字符发生的概率从小到大进行排序;

(2)将最小的两个概率进行两两一合并,之后继续找最小的两个概率进行合并包括前面已经合并的和数;

(3)一步步合并直到最终的根处为1就此形成了一棵二叉树,再进行码字编写,从根部开始树枝处左零右一在,或是左一右零均可以,从根到树叶的部分形成一个码字,依次读出码字形成码表完成最终的编码。

2.二叉树的基本结构及其定义:

完成Huffman编码的主要步骤就是二叉树的建立,二叉树主要有中间节点和树叶的区分,对树叶而言是没有孩子的,而中间节点则是有孩子的;

(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;

(2)哈夫曼码字结构

typedef struct huffman_code_tag //码字数据类型

{

unsigned long numbits;// 该码所用的比特数
       unsigned char *bits;  // 指向该码比特串的指针

}huffman_code;

二.实验流程

(1)读入文件;

(2)第一次扫描文件统计各个字节出现的概率;

(3)建立Huffman树;

(4)将码表以及其他必要信息写入输出文件;

(5)第二次扫描文件,对源文件进行编码输出;

三.主要代码分析

主函数:

#include "huffman.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include "getopt.h"
#pragma comment(lib,"ws2_32.lib")#ifdef WIN32
#include <malloc.h>
extern int getopt(int, char**, char*);
extern char* optarg;
#else
#include <unistd.h>
#endifstatic int memory_encode_file(FILE *in, FILE *out);
static int memory_decode_file(FILE *in, FILE *out);static void
version(FILE *out)
{fputs("huffcode 0.3\n""Copyright (C) 2003 Douglas Ryan Richardson""; Gauss Interprise, Inc\n",out);
}static void
usage(FILE* out)
{fputs("Usage: huffcode [-i<input file>] [-o<output file>] [-d|-c]\n""-i - input file (default is standard input)\n""-o - output file (default is standard output)\n""-d - decompress\n""-c - compress (default)\n""-m - read file into memory, compress, then write to file (not default)\n"//  for huffman statistics"-t - output huffman statistics\n",//out);
}int main(int argc, char** argv)//argc:表示命令行参数的个数,argv:命令行参数指针
{char memory = 0;//memory=0:表示采用文件编码而不是内存编码char compress = 1;//编码int opt;//接受opt的返回值const char *file_in = NULL, *file_out = NULL;const char *file_out_table = NULL;// 输出列表:字符,频率,码长,码字FILE *in = stdin;//标准输入文件FILE *out = stdout;//标准输出文件FILE * outTable = stdout;/* 获得命令行参数. */while((opt = getopt(argc, argv, "i:o:cdhvmt:")) != -1) //演示如何跳出循环,及查找括号对{switch(opt)//opt是定义的iocdhvmt中的某一个{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;// case 't'://输出包含字符,频率,码字等的表file_out_table = optarg;            break;//default://标准错误文件usage(stderr);return 1;}}/* If an input file is given then open it. *///给定输入文件,打开if(file_in){in = fopen(file_in, "rb");if(!in){fprintf(stderr,"Can't open input file '%s': %s\n",file_in, strerror(errno));return 1;}}/* If an output file is given then create it. *///创建输出文件并打开if(file_out){out = fopen(file_out, "wb");if(!out){fprintf(stderr,"Can't open output file '%s': %s\n",file_out, strerror(errno));return 1;}}//输出列表if(file_out_table){outTable = fopen(file_out_table, "w");if(!outTable){fprintf(stderr,"Can't open output file '%s': %s\n",file_out_table, strerror(errno));return 1;}}//if(memory)//memory=1:进行内存编解码{return compress ?memory_encode_file(in, out) : memory_decode_file(in, out);}if(compress)  //compress=1:进行文件编解码huffman_encode_file(in, out,outTable);//elsehuffman_decode_file(in, out);//关闭文件if(in)fclose(in);if(out)fclose(out);if(outTable)fclose(outTable);return 0;
}static int
memory_encode_file(FILE *in, FILE *out)
{//buf:放置输入文件中内容的内存指针//bufout:放置输出文件中内容的内存指针unsigned char *buf = NULL, *bufout = NULL;unsigned int len = 0, cur = 0, inc = 1024, bufoutlen = 0;//检测输入输出文件是否都被成功打开assert(in && out);/* Read the file into memory. */while(!feof(in))//判断是否读到文件尾{unsigned char *tmp;//临时内存指针len += inc;//要重新分配的内存的大小,inc表示cache的大小tmp = (unsigned char*)realloc(buf, len);//realloc与mollac的区别if(!tmp)//判断内存分配是否成功{if(buf)//如果tmp为空,就释放内存free(buf);return 1;}buf = tmp;//否则,buf指向已重新分配的内存//将输入文件中长度为Inc的数据读入buf+cur之后的内存中cur += fread(buf + cur, 1, inc, in);//cur的最终值为读入文件的大小}if(!buf)//如果待写入内存为空,返回1return 1;/* Encode the memory. *///对输入内存进行编码/*cur:表示输入内存长度,即输入文件大小,前面读入文件确定第三个形参是二级指针,实参是指针bufout的地址??????*/if(huffman_encode_memory(buf, cur, &bufout, &bufoutlen)){free(buf);return 1;}//内存编码完成,释放输入内存空间free(buf);//即使内存编码没有完成,也要释放输入内存/* Write the memory to the file. *///将输出内存中的数据写入输出文件if(fwrite(bufout, 1, bufoutlen, out) != bufoutlen){free(bufout);return 1;}free(bufout);//释放输出内存return 0;
}//内存解码,与编码原理基本一致,调用函数
static int memory_decode_file(FILE *in, FILE *out)
{unsigned char *buf = NULL, *bufout = NULL;unsigned int len = 0, cur = 0, inc = 1024, bufoutlen = 0;assert(in && out);/* Read the file into memory. */while(!feof(in)){unsigned char *tmp;len += inc;tmp = (unsigned char*)realloc(buf, len);if(!tmp){if(buf)free(buf);return 1;}buf = tmp;cur += fread(buf + cur, 1, inc, in);}if(!buf)return 1;/* Decode the memory. */if(huffman_decode_memory(buf, cur, &bufout, &bufoutlen)){free(buf);return 1;}free(buf);/* Write the memory to the file. */if(fwrite(bufout, 1, bufoutlen, out) != bufoutlen){free(bufout);return 1;}free(bufout);return 0;
}

getopt.c文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* declarations to provide consistent linkage */
extern char *optarg;
extern int optind;
extern int opterr;int   opterr = 1,        /* if error message should be printed */optind = 1,        /* index into parent argv vector */optopt,          /* character checked for validity */optreset;       /* reset getopt */
char    *optarg;        /* argument associated with option */#define    BADCH   (int)'?'
#define BADARG  (int)':'
#define EMSG    ""/** getopt --*  Parse argc/argv argument vector.*/
int
getopt(int nargc, char * const *nargv, const char* ostr)
{static char *place = EMSG;        /* option letter processing */char *oli;                /* option letter list index */if (optreset || !*place) {        /* update scanning pointer */optreset = 0;if (optind >= nargc || *(place = nargv[optind]) != '-') {place = EMSG;return (EOF);}if (place[1] && *++place == '-') {    /* found "--" */++optind;place = EMSG;return (EOF);}}                  /* option letter okay? */if ((optopt = (int)*place++) == (int)':' ||!(oli =(char *) strchr(ostr, optopt))) {/** if the user didn't specify '-' as an option,* assume it means EOF.*/if (optopt == (int)'-')return (EOF);if (!*place)++optind;if (opterr && *ostr != ':')(void)fprintf(stderr,"%s: illegal option -- %c\n", __FILE__, optopt);return (BADCH);}if (*++oli != ':') {            /* don't need argument */optarg = NULL;if (!*place)++optind;}else {                 /* need an argument */if (*place)           /* no white space */optarg = place;else if (nargc <= ++optind) { /* no arg */place = EMSG;if (*ostr == ':')return (BADARG);if (opterr)(void)fprintf(stderr,"%s: option requires an argument -- %c\n",__FILE__, optopt);return (BADCH);}else               /* white space */optarg = nargv[optind];place = EMSG;++optind;}return (optopt);         /* dump back option letter */
}
四.实验结果



五.实验结果分析
对于已经压缩过的RAR文件而言,已经没有过多的冗余可以压缩了,MP3,MP4等可以压缩的空间也不大,而Word文档以及Excel则可以较大幅度的压缩。

实验三—Huffman编解码相关推荐

  1. 实验三 Huffman编解码算法实现与压缩效率分析

    一.Huffman编解码原理 1. Huffman编码 对原始文件进行Huffman编码,首先需要解决以下几点问题: 文件符号的概率分布情况是怎样的? Huffman树是如何建立的? 建立起Huffm ...

  2. 数据压缩 实验三 Huffman编解码算法实现与压缩效率分析

    实验目的 掌握Huffman编解码实现的数据结构和实现框架, 进一步熟练使用C编程语言, 并完成压缩效率的分析. 实验原理 1.本实验中Huffman编码算法 (1)将文件以ASCII字符流的形式读入 ...

  3. 数据压缩原理 实验三 Huffman编解码算法实现与压缩效率分析

    实验原理 Huffman编码是一种无失真编码方式,是一种可变长编码,它将出现概率大的信源符号短编码,出现概率小的信源符号长编码. 编码步骤: ①将文件以ASCII字符流的形式读入,统计每个符号的发生概 ...

  4. 数据压缩实验三--Huffman编解码及压缩率的比较

    一,Huffman码 1 Huffman 编码 Huffman Coding (霍夫曼编码)是一种无失真编码的编码方式,Huffman编码是可变字长编码(VLC)的一种. Huffman 编码基于信源 ...

  5. 实验三 LZW编解码算法实现与分析

    LZW简述 本部分参考wiki https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch LZW压缩算法在1978年提出,由 Abr ...

  6. [实验三]LZW 编解码算法实现与分析

    目录 一.LZW算法 1.1 编码步骤 1.2 解码步骤 1.3 关于有可能出现当前码字CW不在词典中的情况说明 二.代码实现 2.1 程序说明 2.2 数据结构 2.3 bitio.h 2.4 bi ...

  7. 实验三 LZW编解码实验

    一.LZW算法简介 LZW为词典编码的一种,是通过从输入数据中创建"短语词典".在编码过程中遇到词典中出现的"短语"时,编码器就输出其对应的"序号&q ...

  8. Huffman编解码

    Huffman编解码算法实现与压缩效率分析 一.背景知识及相关公式 1.信源熵 信源熵是信息的度量单位,一般用H表示,单位是比特,对于任意一个随机变量,它的熵定义为,变量的不确定性越大,熵也就越大. ...

  9. 多媒体技术与应用之图像Huffman编解码

    多媒体技术与应用之图像Huffman编解码 一.实验内容 1.了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离 2.熟悉Huffman编码原理 3.使用Huffman编码算法对给定图像文 ...

最新文章

  1. java高深技术总结_一名25K以上的高薪Java程序员总结出的技术以及学习技能
  2. 黄学东出任微软全球人工智能首席技术官,从负责语音技术到微软Azure云的转身
  3. 计算机与人脑_要把人脑连到计算机上!马斯克真敢想,但人类准备好了吗?
  4. 电子工程师都在看什么?送你一份“修炼宝典”
  5. 阿里助手 5.12.2
  6. 笔记本电脑磁盘加密技术
  7. 【 HDU1081 】 To The Max (最大子矩阵和)
  8. 苹果手机绕激活锁之亲身体验
  9. oracle登录卡,【Oracle连接问题】关于windows xp3上oracle连接登录卡住的问题
  10. 可微信打印的共享服务器哪好,基于微信的图片打印分享平台
  11. 数据显示:中国程序员是世界上最牛的程序员
  12. (啤酒,红酒,白酒,料酒)豆瓣(剁椒)鲫鱼做法记录
  13. 利用html5实现的飞雪效果代码实例
  14. pdf合并的工具下载
  15. 雅高集团2021年即将开业的新酒店数量强劲增长
  16. 【数学建模】2022亚太赛A题 结晶器熔炼结晶过程序列图像特征提取与建模分析
  17. 第三届长沙 · 中国 1024 程序员节:共迎算力新时代,开源新未来
  18. 百度知道怎样引流?如何把有共同需求的人精准地引导给我们?
  19. (1)我们的代码被 “送进城里 ” 后发生了什么 ^o^ —— 「进程」篇
  20. 扇贝编程python学习笔记-基础篇5

热门文章

  1. 28-29周学习记录
  2. 微信退款简单实现(复制代码就能在本地运行实现)
  3. 限制玻尔兹曼机(RBM)
  4. ShardingSphere 社区出品|LGTM :数据圈内的周度「热点精选」
  5. java/php/net/pythont海鲜购物淘电商平台设计
  6. CRC校验原理及两种代码实现方法(c语言和labview实现)
  7. 嗨购严选是什么,公司模式制度怎么样?
  8. 鸿蒙系统的制造线,【图】实现万物互联 华为鸿蒙操作系统发布_汽车之家
  9. matlab判断m是否为完数,编写一个函数过程:判断一个已知数m是否是完数(完数就是指该数本身等于它各个因子之和,如6=1+2+3,6就是...
  10. Perl Data::Dumper模块介绍