数据结构实验三Huffman编码二叉树应用.docx
- 文档编号:27089876
- 上传时间:2023-06-26
- 格式:DOCX
- 页数:23
- 大小:300.64KB
数据结构实验三Huffman编码二叉树应用.docx
《数据结构实验三Huffman编码二叉树应用.docx》由会员分享,可在线阅读,更多相关《数据结构实验三Huffman编码二叉树应用.docx(23页珍藏版)》请在冰豆网上搜索。
数据结构实验三Huffman编码二叉树应用
四川大学计算机学院
多媒体课程实验报告
实验名称:
Huffman编码(二叉树应用)
指导教师:
沈琳
姓名:
侯静
学号:
0943041267
班级:
09403014
日期:
2010.12.10
一、实验号题目:
Huffman编码(二叉树应用)
二、实验的目的和要求:
1.要求对文件进行Huffman编码的算法,以及对乙编码文件进行解码的算法,为简单起见,可以假设文件是存放在一个字符向量;
2.熟练掌握二叉树的应用;
3.熟练掌握计算机系统的基本操作方法,了解如何编辑、编译、链接和运行一个C++程序及二叉树上的基本运算;具体要求如下:
最小冗余码/哈夫曼码
●ASCII码/定长码
ab12:
01100001011000100011000100110010
97984950
●哈夫曼码/不定长码
能按字符的使用频度,使文本代码的总长度具有最小值。
例.给定有18个字符组成的文本:
AADATARAEFRTAAFTER
字符
A
D
E
F
T
R
频度
7
1
2
2
3
3
求各字符的哈夫曼码。
(1)统计:
(2)构造Huffman树:
(2)构造Huffman树:
(3)在左分枝标0,右分枝标1:
(4)确定Huffman编码:
字符
A
D
E
F
T
R
频度
7
1
2
2
3
3
编码
0
1010
1011
100
110
111
特点:
任一编码不是其它编码的前缀
例.给定代码序列:
001000111010101011110
文本为:
AAFARADET
4.上机调试程序,掌握查错、排错使程序能正确运行。
三、实验的环境:
1.硬件环境:
intelcorei5460处理器,2G内存
2.软件环境:
windows7,VisualStudio2010Ultimate
四、算法描述:
1.主函数流程图
2.函数Code()流程图
3.函数UnCode()流程图
五、源程序清单:
Huffman.h
constunsignedintn=256;//字符数
constunsignedintm=256*2-1;//结点总数
structHTNode{//压缩用Huffman树结点
unsignedlongweight;//字符频度(权值)
unsignedintparent,lchild,rchild;
};
structBuffer{//字节缓冲压缩用Huffman树
charch;//字节
unsignedintbits;//实际比特数
};
classHuffmanTree{//Huffman树
public:
voidCode();//编码
voidUnCode();//译码
private:
HTNodeHT[m+1];//树结点表(HT[1]到HT[m])
charLeaf[n+1];//叶结点对应字符(leaf[1]到leaf[n])
char*HuffmanCode[n+1];//叶结点对应编码(*HuffmanCode[1]到*HuffmanCode[n])
unsignedintcount;//频度大于零的字符数
unsignedintchar_index[n];//字符对应在树结点表的下标(char_index[0]到char_index[n-1])
unsignedlongsize;//被压缩文件长度
FILE*infp,*outfp;//输入/出文件
Bufferbuf;//字符缓冲
voidStat();//统计字符出现频度并过滤掉频度为零的字符
//在HT[0]~HT[k]中选择parent为-1,树值最小的两个结点s1,s2
voidSelect(unsignedintk,unsignedint&s1,unsignedint&s2);
voidWrite(unsignedintbit);//向outfp中写入一个比特
voidWrite(unsignedintnum,unsignedintk);//向outfp中写入k个比特
voidWriteToOutfp();//强行写入outfp
voidRead(unsignedint&bit);//从infp中读出一个比特
voidRead(unsignedint&num,unsignedintk);//从infp中读出k个比特
intNToBits(unsignedintnum);//0~num之间的整数用二进位表示所需的最少位数
voidCreateFromCodeFile();//由编码文件中存储的树结构建立Huffman树
//由被压缩文件建立Huffman树,将树结构存入编码文件的文件头部中,并求每个字符的Huffman编码
voidCreateFromSourceFile();
};
voidHuffmanTree:
:
Code()//编码
{
charinfName[256],outfName[256];
cout<<"Pleaseinputsourcefilename(sizelessthan4GB):
";//被压缩文件最多4GB
cin>>infName;
if((infp=fopen(infName,"rb"))==NULL){
cout<<"Cannotopenfile:
"< exit (1); } if(feof(infp)! =0){ cout<<"Emptysourcefile: "< exit (1); } cout<<"Pleaseinputcodefilename: "; cin>>outfName; if((outfp=fopen(outfName,"wb"))==NULL){ cout<<"Cannotopenfile: "< exit (1); } cout<<"Pocessing..."< unsignedcharch; unsignedinti,c; for(i=0;i<=n;i++)HuffmanCode[i]=NULL; CreateFromSourceFile(); rewind(infp); ch=fgetc(infp); while(feof(infp)==0){ c=char_index[ch]; for(i=0;i if(HuffmanCode[c][i]=='0')Write(0); elseWrite (1); } ch=fgetc(infp); } WriteToOutfp(); fclose(infp);fclose(outfp); cout<<"Processend."< } voidHuffmanTree: : UnCode() { charinfName[256],outfName[256]; cout<<"Pleaseinputcodefilename: "; cin>>infName; if((infp=fopen(infName,"rb"))==NULL){ cout<<"Cannotopenfile: "< exit (1); } if(feof(infp)! =0){ cout<<"Emptycodefile: "< exit (1); } cout<<"Pleaseinputtargetfilename: "; cin>>outfName; if((outfp=fopen(outfName,"wb"))==NULL){ cout<<"Cannotopenfile: "< exit (1); } cout<<"Pocessing..."< unsignedintbit,c,i; CreateFromCodeFile();//建立Huffman树 Read(bit); for(i=0;i c=2*count-1;//2*count-1为根结点的下标 while((HT[c].lchild! =0||HT[c].rchild! =0)&&(feof(infp)==0)){ if(bit==0)c=HT[c].lchild; elsec=HT[c].rchild; Read(bit); } fputc(Leaf[c],outfp);//将字符写入outfp中 } fclose(infp);fclose(outfp); cout<<"Processend."< } voidHuffmanTree: : Stat() //统计字符出现频度并过滤掉频度为零的字符 { unsignedinti,cha; for(i=1;i<=n;i++)HT[i].weight=0; size=0; rewind(infp); cha=fgetc(infp); while(feof(infp)==0)//统计字符出现频度 { HT[cha+1].weight++; size++; cha=fgetc(infp); } count=0; for(cha=0;cha if(HT[cha+1].weight>0){ count++; Leaf[count]=cha; HT[count].weight=HT[cha+1].weight; char_index[cha]=count; } } } voidHuffmanTree: : Select(unsignedintk,unsignedint&s1,unsignedint&s2) {//s1,s2为权值最小的根,且s1的权值小于s2的权值 unsignedintroot_count=0;//根结点数; unsignedintroot_index[n];//根结点下标; unsignedinttem,i,j; for(i=1;i<=k;i++) if(HT[i].parent==0) root_index[root_count++]=i; s1=root_index[0];s2=root_index[1]; if(HT[s1].weight>HT[s2].weight){ tem=s1;s1=s2;s2=tem; } for(i=2;i j=root_index[i]; if(HT[j].weight s2=j; if(HT[s1].weight>HT[s2].weight){ tem=s1;s1=s2;s2=tem; } } } } voidHuffmanTree: : Write(unsignedintbit)//向outfp中写入一个比特 { buf.bits++; buf.ch=(buf.ch<<1)+bit; if(buf.bits==8){//缓冲区已满,写入outfp fputc(buf.ch,outfp); buf.bits=0; buf.ch=0; } } voidHuffmanTree: : Write(unsignedintnum,unsignedintk)//向outfp中写入k个比特 { Stack unsignedinti,bit; for(i=1;i<=k;i++){ s.push(num&1); num=(num>>1); } for(i=1;i<=k;i++){ s.top(bit); Write(bit); s.pop(); } } voidHuffmanTree: : WriteToOutfp()//强行写入outfp { unsignedintl=buf.bits; if(l>0) for(unsignedinti=0;i<8-l;i++)Write(0); } voidHuffmanTree: : Read(unsignedint&bit)//从infp中读出一个比特 { if(buf.bits==0){ buf.ch=fgetc(infp); buf.bits=8; } bit=(buf.ch&128)>>7; buf.ch=buf.ch<<1; buf.bits--; } voidHuffmanTree: : Read(unsignedint&num,unsignedintk)//从infp中读出k个比特 { unsignedintbit; num=0; for(unsignedinti=0;i Read(bit); num=(num<<1)+bit; } } intHuffmanTree: : NToBits(unsignedintnum)//0~num之间的整数用二进位表示所需的位数 { unsignedintl=0,power=1; while(power<=num){ l++;power=power*2; } returnl; } voidHuffmanTree: : CreateFromCodeFile()//由编码文件中存储的树结构建立Huffman树 { buf.bits=0;//清空缓冲区 buf.ch=0; unsignedintnum,l,i; rewind(infp); fread(&size,sizeof(unsignedlong),1,infp); Read(count,8); count=count+1; for(i=1;i<=count;i++) fread(&Leaf[i],sizeof(char),1,infp); l=NToBits(2*count-1); for(i=1;i<=count;i++){ HT[i].lchild=0; HT[i].rchild=0; } for(i=count+1;i<=2*count-1;i++){ HT[i].lchild=(Read(num,l),num); HT[i].rchild=(Read(num,l),num); } } voidHuffmanTree: : CreateFromSourceFile() //由被压缩文件建立Huffman树,将树结构存入编码文件的文件头部中,并求每个字符的Huffman编码 { Stat();//统计字符出现频度并过滤掉频度为零的字符 //由被压缩文件建立Huffman树 unsignedinti,s1,s2; for(i=1;i<=count;i++)HT[i].parent=HT[i].lchild=HT[i].rchild=0; for(i=count+1;i<=2*count-1;i++){//建立Huffman树 Select(i-1,s1,s2);//选择parent为0,权值最小的两个结点s1,s2 HT[s1].parent=HT[s2].parent=i; HT[i].parent=0;HT[i].lchild=s1;HT[i].rchild=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } //将树结构存入编码文件的文件头部中 unsignedintl; buf.bits=0;//清空缓冲区 buf.ch=0; rewind(outfp); fwrite(&size,sizeof(unsignedint),1,outfp); Write(count-1,8); for(i=1;i<=count;i++) fwrite(&Leaf[i],sizeof(char),1,outfp); l=NToBits(2*count-1); for(i=count+1;i<=2*count-1;i++){ Write(HT[i].lchild,l); Write(HT[i].rchild,l); } //求每个字符的Huffman编码 unsignedintstart,c,f; char*cd;//编码临时变量 for(i=1;i<=n;i++) if(HuffmanCode[i]! =NULL){ delete[]HuffmanCode[i];//释放存储空间 HuffmanCode[i]=NULL; } cd=newchar[count];//分配求编码的工作空间 cd[count-1]='\0';//编码结束符 for(i=1;i<=count;i++){//逐位求Huffman编码 start=count-1;//编码结束符位置 for(c=i,f=HT[i].parent;f! =0;c=f,f=HT[c].parent)//从叶到根求编码 if(HT[f].lchild==c)cd[--start]='0'; elsecd[--start]='1'; HuffmanCode[i]=newchar[count-start];//为第i个字符编码分配空间 strcpy(HuffmanCode[i],&cd[start]);//从cd复制编码到HuffmanCode } delete[]cd; } Huffman.cpp #include"Utility.h" #include"Lk_stack.h" #include"Huffman.h" voidmain() { HuffmanTreehf; charc=0; while(c! ='3') { cout< cout< cout< cout< "; cin>>c; switch(c) { case'1': hf.Code(); break; case'2': hf.UnCode(); } } } 六、运行结果: 七、实验运行情况分析(包括算法、运行结果、运行环境等问题的讨论)。 程序运行时,先应确定需要编码或译码的文件,否则将退出程序,而编码或译码后的文件可以不存在,程序会自动建立相应的.txt文件。 程序的不足在于只能看到编码或译码后的文件,而不能显示各字符相应的编码。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验 Huffman 编码 二叉 应用