数据结构文件压缩.docx

上传人:b****5 文档编号:30602271 上传时间:2023-08-18 格式:DOCX 页数:22 大小:87.98KB
下载 相关 举报
数据结构文件压缩.docx_第1页
第1页 / 共22页
数据结构文件压缩.docx_第2页
第2页 / 共22页
数据结构文件压缩.docx_第3页
第3页 / 共22页
数据结构文件压缩.docx_第4页
第4页 / 共22页
数据结构文件压缩.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

数据结构文件压缩.docx

《数据结构文件压缩.docx》由会员分享,可在线阅读,更多相关《数据结构文件压缩.docx(22页珍藏版)》请在冰豆网上搜索。

数据结构文件压缩.docx

数据结构文件压缩

数据结构实验报告

实验名称:

文件压缩

实验类型:

综合性试验

班级:

20112111

学号:

2011211107

姓名:

冯若航

实验日期:

2003.6.19下午4:

00

1.问题描述

文件压缩

基本要求

哈夫曼编码是一种常用的数据压缩技术,对数据文件进行哈夫曼编码可大大缩短文件的传输长度,提高信道利用率及传输效率。

要求采用哈夫曼编码原理,统计文本文件中字符出现的词频,以词频作为权值,对文件进行哈夫曼编码以达到压缩文件的目的,再用哈夫曼编码进行译码解压缩。

●统计待压缩的文本文件中各字符的词频,以词频为权值建立哈夫曼树,并将该哈夫曼树保存到文件HufTree.dat中。

●根据哈夫曼树(保存在HufTree.dat中)对每个字符进行哈夫曼编码,并将字符编码保存到HufCode.txt文件中。

●压缩:

根据哈夫曼编码,将源文件进行编码得到压缩文件CodeFile.dat。

●解压:

将CodeFile.dat文件利用哈夫曼树译码解压,恢复为源文件。

2.数据结构设计

此类问题,应设计文件的数据结构。

*4压缩头标记

*1文件名长度

*ns文件名

*4源文件长度

*1020huffman树

*1021~EOF文件内容

赫夫曼树节点的数据结构

typedefstructnode

{

longw;//权

shortp,l,r;//父亲,左孩子,右孩子

}HTNODE,*HTNP;//霍夫曼树的结点

 

赫夫曼编码数组元素的数据结构设计

typedefstructhuffman_code

{

BYTElen;//长度

BYTE*codestr;//字符串

}HFCODE;//霍夫曼编码数组元素

3.算法设计

源代码

#define_CRT_SECURE_NO_DEPRECATE

#include

#include

#include

typedefunsignedintUINT;

typedefunsignedcharBYTE;

typedefstructnode

{

longw;//权

shortp,l,r;//父亲,左孩子,右孩子

}HTNODE,*HTNP;//霍夫曼树的结点

typedefstructhuffman_code

{

BYTElen;//长度

BYTE*codestr;//字符串

}HFCODE;//霍夫曼编码数组元素

#defineOK1

#defineERROR-1

#defineUNUSE-1//未链接节点标志

#defineCHAR_BITS8//一个字符中的位数

#defineINT_BITS32//一个整型中的位数

#defineHUFCODE_SIZE256//霍夫曼编码个数

#defineBUFFERSIZE256//缓冲区大小大小

#defineUINTSIZEsizeof(UINT)

#defineBYTESIZEsizeof(BYTE)

#defineTAG_ZIGHEAD0xFFFFFFFF//压缩文件头标

#defineMAX_FILENAME512

//函数声明

//压缩模块

intCompress(char*SourceFilename,char*DestinationFilename);//压缩调用

intInitializing(char*SourceFilename,FILE**inp,char*DestinationFilename,FILE**outp);//初始化文件工作环境

longAnalysisFiles(FILE*in,longfrequency[]);//计算每个不同字节的频率以及所有的字节数

intCreateHuffmanTree(longw[],intn,HTNODEht[]);//生成霍夫曼树

intHuffmanTreeCoding(HTNPhtp,intn,HFCODEhc[]);//霍夫曼编码

intSearch(HTNPht,intn);//查找当前最小权值的霍夫曼树节点并置为占用

BYTEChar2Bit(constBYTEchars[CHAR_BITS]);//将一个字符数组转换成二进制数字

intSearch(HTNPht,intn);//查找当前最小权值的霍夫曼树节点并置为占用

intWriteZipFiles(FILE*in,FILE*out,HTNPht,HFCODEhc[],char*SourceFilename,longsource_filesize);//写压缩文件

//解压缩模块

intDeCompress(char*SourceFilename,char*DestinationFilename);//解压缩调用

intInitializing_Dezip(char*SourceFilename,FILE**inp,char*DestinationFilename,FILE**outp);//为处理解压缩流程初始化文件

voidReadHuffmanTree(FILE*in,shortmini_ht[][2]);//从待解压缩文件中读取huffman树

intWriteDeZipFiles(FILE*in,FILE*out,shortmini_ht[][2],longbits_pos,longDst_Filesize);//写解压缩文件

voidErrorReport(interror_code);//报错

//函数定义

//函数实现

//压缩

intCompress(char*SourceFilename,char*DestinationFilename)

{

FILE*in,*out;//输入输出流

inti;//计数变量

floatCompress_rate;//存放压缩率

HFCODEhc[HUFCODE_SIZE];//存放256个字符的huffman编码

HTNODEht[HUFCODE_SIZE*2-1];//256个字符的huffman树需要2*256-1=511个节点。

longfrequency[HUFCODE_SIZE],source_filesize,Dst_Filesize=0;//字符频率数组,源文件,目标文件。

 

//处理待压缩与压缩文件文件

Initializing(SourceFilename,&in,DestinationFilename,&out);

puts("LoadingFiles...");

//处理各个字符的频率,并输出原始文件长度

source_filesize=AnalysisFiles(in,frequency);

puts("LoadingComplete!

NowAnalysising...");

printf("Originalsize:

%ldByte\n",source_filesize);

//创建Huffman树

CreateHuffmanTree(frequency,HUFCODE_SIZE,ht);

//Huffman编码

puts("HuffmanTreeInitializedSuccessfully,HuffmanCodingProcessing...");

HuffmanTreeCoding(ht,HUFCODE_SIZE,hc);

 

//计算目标文件长度

for(i=0;i

{//计算位的个数,计算每个字符的频数与其编码长度乘积之和

Dst_Filesize+=frequency[i]*hc[i].len;

}//将文件主体部分的位个数转换为字节个数;

Dst_Filesize=Dst_Filesize%8==0?

Dst_Filesize/8:

Dst_Filesize/8+1;

for(i=0;i

{//huffmantree长度

Dst_Filesize+=2*sizeof(short);

}

Dst_Filesize+=strlen(SourceFilename)+1;//源文件名占用空间

Dst_Filesize+=sizeof(long);//源文件名长度信息占用空间

Dst_Filesize+=UINTSIZE;//文件头长度

Compress_rate=(float)Dst_Filesize/source_filesize;//压缩率

 

puts("CodingSuccessfully.Nowproducingzipfiles...");

printf("CompressedFileSize:

%ldByte,radiation:

%%%.2lf\n",Dst_Filesize,Compress_rate*100);

//生成压缩文件

WriteZipFiles(in,out,ht,hc,SourceFilename,source_filesize);

puts("CompressComplete!

");

//擦屁股

fclose(in);

fclose(out);//关闭文件

for(i=0;i

{

free(hc[i].codestr);

}

returnOK;

}

intInitializing(char*SourceFilename,FILE**inp,char*DestinationFilename,FILE**outp)

{

if(strcmp(SourceFilename,DestinationFilename)==0)

{//重名判断

returnERROR;

}

printf("SourceFile:

%s,DestinationFile:

%s\n",SourceFilename,DestinationFilename);

if((*outp=fopen(DestinationFilename,"wb"))==NULL)

{//文件打开错误

returnERROR;

}

if((*inp=fopen(SourceFilename,"rb"))==NULL)

{//文件打开错误

returnERROR;

}

returnOK;

}

longAnalysisFiles(FILE*in,longfrequency[])

{

inti,read_len;

BYTEbuf[BUFFERSIZE];//缓冲区

longfilesize;//文件总长

for(i=0;i

{

frequency[i]=0;//初始化所有字符频率为0

}

fseek(in,0L,SEEK_SET);//将文件定位符指向文件开头

read_len=BUFFERSIZE;//设置读入长度=缓冲区长度

while(read_len==BUFFERSIZE)//每当读取字符长度达到缓冲区长度时

{

read_len=fread(buf,1,BUFFERSIZE,in);

for(i=0;i

{

frequency[*(buf+i)]++;//统计字频

}

}

for(i=0,filesize=0;i

{

filesize+=frequency[i];//计算文件长度,计算方法是把所有字符的频数相加

}

returnfilesize;

}

intSearch(HTNPht,intn)

{

inti,x;

for(x=0;x

{

if(ht[x].p==UNUSE)break;//找到第一个没有使用的叶子节点,跳出

}

for(i=x;i

{

if(ht[i].p==UNUSE&&ht[i].w

{

x=i;//找权值最小的叶子节点

}

}

ht[x].p=-2;//将叶子节点占用

returnx;

}

intCreateHuffmanTree(longw[],intn,HTNODEht[])

{

intm,i,s1,s2;

if(n<1)returnERROR;

m=2*n-1;//霍夫曼树节点总数=叶子数*2-1

if(ht==NULL)returnERROR;

for(i=0;i

{

ht[i].w=w[i],ht[i].p=ht[i].l=ht[i].r=UNUSE;//初始化叶子节点

}

for(;i

{

ht[i].w=ht[i].p=ht[i].l=ht[i].r=UNUSE;//初始化分支节点

}

for(i=n;i

{//循环至m-n个分支节点全部被使用完为止

s1=Search(ht,i);

s2=Search(ht,i);//找到权值最小的两个节点,这里通过两次调用寻找最小权值的函数search解决问题

ht[s1].p=ht[s2].p=i;//设置父节点

ht[i].l=s1,ht[i].r=s2;//设置孩子

ht[i].w=ht[s1].w+ht[s2].w;//设置权为两个孩子权之和

}

returnOK;

}

intHuffmanTreeCoding(HTNPhtp,intn,HFCODEhc[])

{

inti,j,p,codelen;//codelen:

临时字符数组长度变量

BYTE*code=(BYTE*)malloc(n*BYTESIZE);//临时字符数组,为每一个字符的编码申请一个字节的空间

for(i=0;i

{//从当前节点到根节点逆向求huffman编码,遍历所有叶子节点。

for(p=i,codelen=0;p!

=2*n-2;p=htp[p].p,codelen++)

{//循环到根节点为止

code[codelen]=(htp[htp[p].p].l==p?

0:

1);//第i位编码:

p节点如果是其父亲的:

左孩子:

0;右孩子:

1

}

if((hc[i].codestr=(BYTE*)malloc((codelen)*BYTESIZE))==NULL)

{

returnERROR;//分配叶子节点huffman编码的空间,长度为

}

hc[i].len=codelen;//该字符编码的码长

for(j=0;j

{

hc[i].codestr[j]=code[codelen-j-1];//反转(因为原来是逆的)

}

}

free(code);//擦屁股

returnOK;

}

BYTEChar2Bit(constBYTEchars[CHAR_BITS])

{

inti;

BYTEbits=0;

bits|=chars[0];

for(i=1;i

{

bits<<=1;//左移或实现

bits|=chars[i];

}

returnbits;

}

intWriteZipFiles(FILE*in,FILE*out,HTNPht,HFCODEhc[],char*SourceFilename,longsource_filesize)

{

UINTi,Read_Counter,Write_Counter,zip_head=TAG_ZIGHEAD;//读缓存计数器,写缓存计数器,压缩文件头标

BYTEwrite_char_counter,code_char_counter,copy_char_counter;//写字符计数器,huffman码字符计数器,复制字符计数器

BYTEread_buf[BUFFERSIZE],write_buf[BUFFERSIZE],write_chars[CHAR_BITS];//读缓存,写缓存,转换字符数组,

BYTEfilename_size=strlen(SourceFilename);//文件名长度

HFCODE*Cur_HuffCode;//当前数据的huffman编码指针

//预处理

fseek(in,0L,SEEK_SET);//定位读文件到文件开始处

fseek(out,0L,SEEK_SET);//定位写文件到文件开始处

fwrite(&zip_head,UINTSIZE,1,out);//写入文件头标示符

fwrite(&filename_size,BYTESIZE,1,out);//写入源文件名长度

fwrite(SourceFilename,sizeof(char),filename_size,out);//写入源文件名

fwrite(&source_filesize,sizeof(long),1,out);//写入源文件长度

for(i=HUFCODE_SIZE;i

{//写huffman树的左右孩子(前HUFCODE_SIZE个节点无孩子,不写)

fwrite(&(ht[i].l),sizeof(ht[i].l),1,out);//写入左孩子

fwrite(&(ht[i].r),sizeof(ht[i].r),1,out);//写入右孩子

}

//写正文

Write_Counter=write_char_counter=0;//写缓冲计数器以及写字符计数器清0

Read_Counter=BUFFERSIZE;//置读缓存字符数

//当读入的缓存字符数不等于缓存时,文件读完,退出循环

while(Read_Counter==BUFFERSIZE)

{

Read_Counter=fread(read_buf,1,BUFFERSIZE,in);//读入大小为BUFFSIZE的数据到读缓存

//为每个缓存的数据找huffman编码

for(i=0;i

{

Cur_HuffCode=&hc[read_buf[i]];//当前数据的huffman编码位置

code_char_counter=0;//当前数据huffman编码字符的计数器清0

//当huffman编码字符的计数器等于码长时,转换完毕退出

while(code_char_counter!

=Cur_HuffCode->len)

{//获取本次复制字符的长度为可用写字符长度与可用huffman编码长度中的较小者

copy_char_counter=(CHAR_BITS-write_char_counter>Cur_HuffCode->len-code_char_counter?

Cur_HuffCode->len-code_char_counter:

CHAR_BITS-write_char_counter);

//复制一段字符

memcpy(write_chars+write_char_counter,Cur_HuffCode->codestr+code_char_counter,copy_char_counter);

write_char_counter+=copy_char_counter;//写字符计数器增加

code_char_counter+=copy_char_counter;//编码字符计数器增加

//当写字符计算器满=8时

if(write_char_counter==CHAR_BITS)

{

write_char_counter=0;//写字符计数器清0

//当写缓存满时

write_buf[Write_Counter++]=Char2Bit(write_chars);//转化写字符为二进制数并存入写缓存

if(Write_Counter==BUFFERSIZE)

{

fwrite(write_buf,1,BUFFERSIZE,out);//输出到文件

Write_Counter=0;//写缓存清0

}

}

}

}

}

fwrite(write_buf,1,Write_Counter,out);//写缓存中剩余数据输出到文件,擦屁股

//当写字符数组中还有字符未转换

if(write_char_counter!

=0)

{

write_char_counter=Char2Bit(write_chars);//转化为二级制数据

fwrite(&write_char_counter,1,1,out);//输出到文件

}

returnOK;

}

//解压缩

intDeCompr

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 财务管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1