用哈夫曼编码实现文件压缩实验报告管理资料.docx
《用哈夫曼编码实现文件压缩实验报告管理资料.docx》由会员分享,可在线阅读,更多相关《用哈夫曼编码实现文件压缩实验报告管理资料.docx(17页珍藏版)》请在冰豆网上搜索。
![用哈夫曼编码实现文件压缩实验报告管理资料.docx](https://file1.bdocx.com/fileroot1/2022-11/26/2f642e4d-9af0-47a2-bafd-8b2291276ed1/2f642e4d-9af0-47a2-bafd-8b2291276ed11.gif)
用哈夫曼编码实现文件压缩实验报告管理资料
《用哈夫曼编码实现文件压缩》
实验报告
课程名称数据结构B
实验学期2013至2014学年第一学期
学生所在系部计算机学院
年级2013专业班级
学生姓名学号
任课教师
实验成绩
一、实验题目:
用哈夫曼编码实现文件压缩
二、实验目的:
1、了解文件的概念。
2、掌握线性链表的插入、删除等算法。
3、掌握Huffman树的概念及构造方法。
4、掌握二叉树的存储结构及遍历算法。
5、利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。
三、实验设备与环境:
微型计算机、Windows系列操作系统、VisualC++
四、实验内容:
根据输入小写英文字母和输入的对应权值创建哈夫曼树,可以求出每个小写英文字母的哈夫曼编码,将文本中的字母对应的哈夫曼编码写入文本中,实现对文本的编码。
五、概要设计:
(1)构造Hufffman树的Hufffman算法
构造Huffman树步骤:
1.根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树,起权值为wj。
2.在森林中选取两棵根结点权值最小和次小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。
3.在森林中删除这两棵树,同时将新得到的二叉树加入森林中。
重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。
算法结构如图:
(2)Huffman编码:
数据通信用的二进制编码
思想:
根据字符出现频率编码,使电文总长最短
编码:
根据字符出现频率构造Huffman树,然后将树中结点引向其左孩子的分支标“0”,引向其右孩子的分支标“1”;每个字符的编码即为从根到每个叶子的路径上得到的0、1序列。
(3)文本编码
读取存放在文本中的字母,一对一的进行编译,将对应的编码存放到另一个文本中。
六、详细设计:
#include<>
#include<>
#include<>
//树结点定义
typedefstruct
{
intweight;
intparent;
intlchild;
intrchild;
}HTNode,*HuffmanTree;
staticcharN[100];//用于保存字符
//赫夫曼编码,char型二级指针
typedefchar**HuffmanCode;
//封装最小权结点和次小权结点
typedefstruct
{
ints1;
ints2;
}MinCode;
//函数声明
voidError();
HuffmanCodeHuffmanCoding(HuffmanTree&HT,HuffmanCodeHC,int*w,intn);
MinCodeSelect(HuffmanTreeHT,intn);
//当输入1个结点时的错误提示
voidError()
{
printf("一个字符不进行编码!
\n");
exit
(1);
}
//构造赫夫曼HT,编码存放在HC中,w为权值,n为结点个数
HuffmanCodeHuffmanCoding(HuffmanTree&HT,HuffmanCodeHC,int*w,intn)
{
inti,s1=0,s2=0;
HuffmanTreep;
char*cd;
intf,c,start,m;
MinCodemin;
if(n<=1)
{
Error();//只有一个结点不进行编码,直接exit
(1)退出
}
m=2*n-1;//赫夫曼码需要开辟的结点大小为2n-1
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//开辟赫夫曼树结点空间m+1
//初始化n个叶子结点
for(p=HT,i=0;i<=n;i++,p++,w++)
{
p->weight=*w;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
//将n-1个非叶子结点的初始化
for(;i<=m;i++,p++)
{
p->weight=0;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
//构造赫夫曼树
for(i=n+1;i<=m;i++)
{
min=Select(HT,i-1);//找出最小和次小的两个结点
s1=;//最小结点下标
s2=;//次小结点下标
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;//赋权和
}
//打印赫夫曼树
printf("HTList:
\n");
printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n");
for(i=1;i<=m;i++)
{
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\t\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
//从叶子结点到根节点求每个字符的赫夫曼编码
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
cd=(char*)malloc(n*sizeof(char*));//为赫夫曼编码动态分配空间
cd[n-1]='\0';//编码结束符
//求叶子结点的赫夫曼编码
for(i=1;i<=n;i++)
{
start=n-1;
//定义左子树为0,右子树为1
/*
从最下面的1号节点开始往顶部编码(逆序存放),然后编码2号节点,3号......
*/
for(c=i,f=HT[i].parent;f!
=0;c=f,f=HT[f].parent)
{
if(HT[f].lchild==c)
cd[--start]='0';
else
cd[--start]='1';
}
//为第i个字符分配编码空间
HC[i]=(char*)malloc((n-start)*sizeof(char*));
//将当前求出结点的赫夫曼编码复制到HC
strcpy(HC[i],&cd[start]);
}
free(cd);
returnHC;
}
MinCodeSelect(HuffmanTreeHT,intn)
{
intmin,secmin;
inttemp=0;
inti,s1,s2,tempi=0;
MinCodecode;
s1=1;
s2=1;
min=999999;//足够大
//找出权值weight最小的结点,下标保存在s1中
for(i=1;i<=n;i++)
{
if(HT[i].weight{
min=HT[i].weight;
s1=i;
}
}
secmin=999999;//足够大
//找出权值weight次小的结点,下标保存在s2中
for(i=1;i<=n;i++)
{
if((HT[i].weight=s1)&&HT[i].parent==0)
{
secmin=HT[i].weight;
s2=i;
}
}
//放进封装中
=s1;
=s2;
returncode;
}
voidCompression(HuffmanCodeHC)//翻译原文档字符为赫夫曼编码
{
FILE*fp1,*fp2;
charch;
if((fp1=fopen("","r"))==NULL)
exit(0);
if((fp2=fopen("","a"))==NULL)
exit(0);
ch=fgetc(fp1);
while((int)ch!
=-1)
{
switch(ch)
{
case'a':
fputs(HC[1],fp2);break;
case'b':
fputs(HC[2],fp2);break;
case'c':
fputs(HC[3],fp2);break;
case'd':
fputs(HC[4],fp2);break;
case'e':
fputs(HC[5],fp2);break;
case'f':
fputs(HC[6],fp2);break;
case'g':
fputs(HC[7],fp2);break;
case'h':
fputs(HC[8],fp2);break;
case'i':
fputs(HC[9],fp2);break;
case'j':
fputs(HC[10],fp2);break;
case'k':
fputs(HC[11],fp2);break;
case'l':
fputs(HC[12],fp2);break;
case'm':
fputs(HC[13],fp2);break;
case'n':
fputs(HC[14],fp2);break;
case'o':
fputs(HC[15],fp2);break;
case'p':
fputs(HC[16],fp2);break;
case'q':
fputs(HC[17],fp2);break;
case'r':
fputs(HC[18],fp2);break;
case's':
fputs(HC[19],fp2);break;
case't':
fputs(HC[20],fp2);break;
case'u':
fputs(HC[21],fp2);break;
case'v':
fputs(HC[22],fp2);break;
case'w':
fputs(HC[23],fp2);break;
case'x':
fputs(HC[24],fp2);break;
case'y':
fputs(HC[25],fp2);break;
case'z':
fputs(HC[26],fp2);break;
default:
printf("没有编码!
\n");
}
ch=fgetc(fp1);
}
fclose(fp1);
fclose(fp2);
}
voidmain()
{
HuffmanTreeHT=NULL;
HuffmanCodeHC=NULL;
int*w=NULL;
inti,n;
printf("输入字符:
");
gets(N);
n=strlen(N);
w=(int*)malloc((n+1)*sizeof(int*));//开辟n+1个长度的int指针空间
w[0]=0;
printf("输入结点权值:
\n");
//输入结点权值
for(i=1;i<=n;i++)
{
printf("w[%d]=",i);
scanf("%d",&w[i]);
}
//构造赫夫曼树HT,编码存放在HC中,w为权值,n为结点个数
HC=HuffmanCoding(HT,HC,w,n);
//输出赫夫曼编码
printf("赫夫曼:
\n");
printf("Number\t\tWeight\t\tCode\n");
for(i=1;i<=n;i++)
{
printf("%c\t\t%d\t\t%s\n",N[i-1],w[i],HC[i]);
}
Compression(HC);
}
选取权值最小的结点的算法:
选取权值次小的结点的算法:
哈夫曼树建立的算法:
开始
读入n,S1,S2的值
i=n+1
i<=2n-1
否
是
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
i++
输出S1的值
结束
哈夫曼编码的算法:
开始
读入n
i=1
i<=n
否
是
start=1
c=i
f=HT[i].parent
f!
=0
否
是
HT[f].lchild==c
否
cd[--start]='1'
是
cd[--start]='0'
i++
输出cd的值
结束
七、测试结果及分析:
4.输出哈夫曼树:
5.字符对应编码:
6.要编码的文本:
7.编译后的文本:
八、教师评语:
教师评价
评定项目
A
B
C
D
评定项目
A
B
C
D
算法正确
界面美观,布局合理
程序结构合理
操作熟练
语法、语义正确
解析完整
实验结果正确
文字流畅
报告规范
题解正确
其他:
评价教师签名:
年月日