哈夫曼压缩

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2012-2013学年第二学期《高级语言程序设计》

课程设计报告

题目:采用哈夫曼技术的压缩软件

专业:计算机科学与技术

班级:09计科(2)班

姓名:方刚

指导教师:代美丽

成绩:

计算机与信息工程系

2013年4月19日

计算机与信息工程系《数据库系统应用设计》课程设计报告

目录

1.设计内容及要求 (1)

1.1内容 (1)

1.2要求 (1)

2.概要设计 (1)

2.1函数结构设计 (1)

2.2数据结构设计 (1)

3.设计过程或程序代码. (2)

3.1compress函数 (2)

3.2建立哈夫曼树 (2)

3.3uncompress函数 (6)

4.设计结果与分析. (8)

4.1程序运行截图 (8)

4.1.1原始菜单界面 (8)

4.1.2压缩目标文件 (9)

4.1.3还原为原文件 (9)

4.1.4退出 (10)

4.2分析 (10)

5.参考文献. (11)

采用哈夫曼技术的压缩软件

1设计内容及要求

1.1 内容

设计目标是要实现哈夫曼压缩的编码器和译码器。码器工作如下:首先读入待压缩文件为了保证与原文件信息完全一致,对文件的读写都采用二进制的方式进行。然后建立并分析字母表,最多只有256种可能的符,对每种字符出现的频度进行统计,以频度作为建立哈夫曼树的权值。频度表建立好以后,可以建立哈夫曼树,对出现的每种字符进行哈夫曼编码。此时再读入原文件,逐个字节进行编码,将得到的编码流逐个写入文件。译码过程相对简单:读入被压缩文件,将其解释为比特流,根据哈夫曼树对比特流逐个译码,将译码结果逐个写到磁盘文件。

1.2要求

准备一个文件,统计该文件中各种字符的频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成源文件。

2概要设计

2.1函数结构设计

在head.h文件中共有3个函数,分别为:

void Select(int k,int &s1,int &s2)

void compress()

void uncompress()

其中void Select(int k,int &s1,int &s2)是在void compress()中调用的,他的功能是在K个元素中选择权值最小的两个结点S1,S2;

void compress()和void uncompress()是在a.cpp的main函数中被调用的,他们的功能分别是压缩和解压缩。

函数结构图如下:

2.2数据结构设计

哈夫曼算法的实现可以采用链表结构生成哈夫曼树,但是效率比较低,也可以使用堆排序,这里采用的是线形表的顺序存储结构:

struct head

{

unsigned char b; //记录字符在数组中的位置 long count; //字符出现频率(权值)

long parent,lch,rch; //定义哈夫曼树指针变量

char bits[256]; //定义存储哈夫曼编码的数组

}

该存储结构在二叉树中的结点结构如下:

3设计过程或程序代码

功能设计

3.1compress函数:

该函数将完成压缩目标文件的功能,首先输入文件名,读取目标文件

ifp=fopen(filename,"rb"),这里”rb”是按二进制方式进行读操作,输入压缩后的文件名fopen(outputfile,"wb"),其中”wb”是打开或建立一个二进制文件,只允许写数据。(filename为需要压缩的文件名,outputfile为完成压缩后的文件名) while(!feof(ifp))

{

fread(&c,1,1,ifp);

fread(buffer,size,count,fp),

header[c].count++; //字符重复出现频率加1

flength++; //出现字符则原文长度加1

}

feof()为文件检测函数,若文件没有结束返回是0,当文件结束时返回1。

fread()是从一个流中读数据,fread(buffer,size,count,fp),其中buffer是一个指针,在fread函数中,它表示存放输入数据的首地址。size 表示数据块的字节数。count 表示要读写的数据块块数。fp 表示文件指针。

for(i=0;i<512;i++)

{

if(header[i].count!=0) header[i].b=(unsigned char)i; //如果该字符出现过,将他的哈夫曼码值及其对应的ASCII码存放在一维数组header[i]中,且编码表中的下标和ASCII码满足顺序存放关系。

else header[i].b=0;

header[i].parent=header[i].lch=header[i].rch=-1; //是对结点进行初始化。

}

3.2建立哈夫曼树:

for(i=0;i<256;i++) //根据频率(权值)大小,对结点进行排序,选择较小的结点进树。

{

for(j=i+1;j<256;j++)

{

if(header[i].count

{

tmp=header[i];

header[i]=header[j];

header[j]=tmp;

}

}

}

根据哈夫曼树的性质,n个叶子结点(权)需要2n-1个结点来构建一棵哈夫曼树:

for(i=n;i

{

Select(i-1,s1,s2);

header[s1].parent=header[s2].parent=i;

header[i].lch=s1;

header[i].rch=s2;

header[i].count=header[s1].count+header[s2].count;

}

header[i].lch=s1; //计算左分支权值大小;

header[i].rch=s2; //计算右分支权值大小;

header[s1].parent=header[s2].parent=i; //依据parent域值(结点层数)确定树中结点之间的关系;

header[i].count=header[s1].count+header[s2].count; //父结点的权值为其左孩子和右孩子权值之和;

构建哈夫曼树时用到了一个Select()函数:在K个元素中选择父结点不为-1的权值最小的两个结点S1,S2;

void Select(int k,int &s1,int &s2)

{

s1,s2=0;

long min1=9999999;

for(int j=1;j

if (header[j].parent!=-1)

{

if (header[j].count

{

s2=s1;

s1=j;

}

相关文档
最新文档