数据结构课程设计报告
题目: 哈夫曼编码与文件压缩
学号:
姓名:
u201014516
董贝青
指导老师:
许贵平
院系班级:
计科 1010
目录
一、实验目的………………………………………………………1
二、实验环境………………………………………………………1
三、实验内容………………………………………………………1
四、实验要求………………………………………………………1
五、设计概要………………………………………………………1
六、源代码及流程图………………………………………………2
七、数据测试………………………………………………………16
八、实验感受………………………………………………………19
一、实验目的
1、掌握二叉树、哈夫曼树的概念、性质与存储结构
2、掌握哈夫曼算法,能够利用其实现哈夫曼编码,并应用于文件压缩。
3、提高综合运用只是的技能与实践能力。
二、实验环境
1、Windows 7
2、Visual Studio 2012
三、 实验内容
分析与设计哈夫曼树的存储结构,实现哈夫曼算法以及编码与译码基本功
能,并对任意文本文件利用哈夫曼编码进行压缩得到压缩文件,然后进行解压缩
得到解压文件。
四、实验要求
(1)要求界面友好,输入文本文件可带路径(如:D:\doc\original.txt),哈夫曼
算法所得到的压缩文件名为*.cod,哈夫曼树也以文件形式保存,文件名为*.hfm。
(2)显示压缩比、压缩时间、解压时间与对应的编码表。
五、设计概要
统计文本文件中各字符的频度并作为权值生成哈夫曼树,并利用哈夫曼树进
行二进制编码。
压缩部分
1. 构造哈夫曼树,对其进行前缀编码
(1)扫描待压缩文件,得出各字符出现频率。
(2)根据给定的 n 个权值{W1,W2,...Wn}构成 n 棵二叉树的集合 F={T1,T2,…,
Tn},每棵二叉树 Ti 中只有一个带权为 Wi 的根节点,其左右子树均空。
(3)在 F 中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二
叉树,且值新的二叉树的根节点的权值为其左右子树上根节点的全值之和。
(4)在 F 中删除这两棵树。同时将新得到的二叉树加入 F 中。
重置(2)和(3),直到 F 只含一棵树为止。这棵树便是哈夫曼树。
2. 由 Huffman 树得到各字符前缀编码。
3. 根据前缀编码,对文件中各个字符进行编码,并按每八位一次写入压缩
文件。
4. 处理剩余不到八位部分,写入压缩文件。
5. 将前缀编码及相关信息写入压缩文件。
1
6. 关闭指针,完成压缩。计算压缩率。
解压部分
1. 读入压缩文件长度和源文件长度。读入前缀编码。
2. 对文件中各字符解码,写入解压文件。
3. 判断解压文件是否完好(对比压缩前文件长度),关闭指针,完成解压。
六、源码及注释
#include
#include
#include
#include
#include
#include
#define N 255
#define M 2*N - 1
void Initiate();
void Compress();
void Uncompress();
void CreateHFMtree();
void CreateHFMcode();
void SaveHFMcode();
void PrintHFMcode();
void PrintHFMtree();
void SaveHFMtree();
//哈夫曼树初始化函数
//压缩文件
//解压文件
//生成哈夫曼树
//生成哈夫曼编码
//保存哈夫曼编码表
//打印哈夫曼编码
//打印哈夫曼树
//保存哈夫曼树
FILE *fp;
int flag=0;
int n1;
int total = 0;
clock_t begin,finish;
double duration;
typedef struct
{
//文件字节总长
//计时
//字符
//权值
char ch;
int weight;
int parent,lchild,rchild;
char code[N];
}HFMtree;
HFMtree tree[M],ex;
//哈夫曼树
//ex 为排序时交换所用的临时变量
2
int main()
{
int x,n=0;
while(1)
{
system("cls");
printf("--------哈夫曼压缩与解压--------\n\n");
printf("1.载入文件\t");
printf("2.显示哈夫曼编码表\n");
printf("3.显示哈夫曼树\t");
printf("4.压缩文件\n");
printf("5.解压文件\t");
printf("6.退出\n\n");
printf("---------------------------------\n");
printf("请输入功能号 1-6:");
scanf("%d", &x);
switch(x)
{
case 1:
Initiate();
if(flag==1){
CreateHFMtree();
CreateHFMcode();
SaveHFMcode();
SaveHFMtree();
//生成哈夫曼树
//生成哈夫曼编码
//保存哈夫曼编码
//保存哈夫曼树
}
system("pause");
break;
case 2:
system("cls");
PrintHFMcode();
system("pause");
break;
case 3:
system("cls");
PrintHFMtree();
system("pause");
break;
case 4:
begin = clock();
3
Compress();
finish = clock();
duration = (double)(finish - begin) / CLOCKS_PER_SEC;
printf("压缩用时%lf 秒\n",duration);
system("pause");
break;
case 5:
Uncompress();
system("pause");
break;
case 6:
return 0;
default:
fflush(stdin);
}
}
return 0;
}
void Initiate()
{
//记录文本中的字符
char filename1[20];
char c;
int i;
getchar();
printf("请输入需要被压缩的文件的路径:");
gets(filename1);
fp=fopen(filename1,"rb");
if(fp==NULL){
//以只读方式打开二进制文件
printf("\n 文件打开失败! ");
return;
}
while(!feof(fp)){
fread(&c,1,1,fp);
tree[c].weight++;
total++;
}
total--;
tree[c].weight--;
for(i=0;i
tree[i].ch=0;
tree[i].parent=-1;
tree[i].lchild=-1;
tree[i].rchild=-1;
}
flag=1;
}
void CreateHFMtree()
{
int i, min, n, m, j, temp;
for(i=0;i
tree[j].weight){
temp=j;
min=tree[j].weight;
continue;
}
}
tree[i].weight=tree[temp].weight;
tree[temp].parent=i;
tree[i].lchild=temp;
min=10000000;
for(j=0;jcontinue;
if(min>tree[j].weight){
temp=j;
min=tree[j].weight;
continue;
}
}
tree[i].weight+=tree[temp].weight;
tree[i].rchild=temp;
tree[temp].parent=i;
}
}
void CreateHFMcode()
{
int i, j, f, n;
n = n1;
for(i=0;i