数据结构课程设计赫夫曼编码系统.docx
《数据结构课程设计赫夫曼编码系统.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计赫夫曼编码系统.docx(38页珍藏版)》请在冰豆网上搜索。
数据结构课程设计赫夫曼编码系统
《数据结构》课程设计报告
课程名称:
赫夫曼编码系统
姓名:
学号:
专业:
班级:
指导教师:
二〇一二年十二月
目录Contents
1.课程小组2
1.1.小组成员及分工2
2.设计目的和要求2
3.需求分析2
4.设计说明2
4.1.文件编码(加密)2
4.2.文件解码(解密)3
5.详细设计3
5.1.程序主体结构3
5.2.主要算法说明3
5.2.1.Huffman树3
5.2.2.Huffman编码5
5.2.3.字符权重计算6
5.2.4.字符解码9
6.实验结果10
6.1.实验结果说明10
6.2.程序运行截图11
7.设计体会12
8.参考文献13
9.附:
程序代码13
1.课程小组
1.1.小组成员及分工
…
2.设计目的和要求
通过课程设计,让学生进一步熟悉与巩固数据结构中常用算法,加深体会利用数据结构的算法解决实际问题的能力,培养学生进行复杂程序设计的技能,提高学生的思维能力、并促进其综合应用能力、分析能力和团队合作能力的提高。
3.需求分析
随着网络信息科技的不断高速发展,网络上的问题也不断显露出来,特别是人们特别关注的安全隐私问题,所以文件的传输安全性要特别地亟待解决和提高。
本次的课程设计以赫夫曼编码为题,设计出赫夫曼文件编码系统,旨在对文件中的内容进行分析、统计、处理,进而按照赫夫曼编码的理论,对文件进行简单加密。
特别是,不同的文本文件有不同的字符处理形式,所以因此每一个文本都会有一个相应的密钥,用于对文本的解码。
4.设计说明
本次编写的程序按着对文件的编码(加密)和解码(解密)的两大步骤展开。
4.1.文件编码(加密)
首先选择文件编码程序。
进入程序后,会要求操作人员选择将要编码的文件,并将其导入到程序中,程序正确导入文件后将会对文件从开始至结束扫描一遍,对文件中的字符进行统计,在最后计算出每个字符出现的频率,并将频率换算成每个字符相应的权重。
然后根据得到的字符权重,构造赫夫曼树并因此完成赫夫曼编码(至此,文件的导入分析过程已完成)。
然后让操作人员选择对文件进行编码。
此时,程序将会继续打开文件,继续扫描一遍,并在扫描的过程中将扫描到得字符根据刚才编好的赫夫曼编码进行对照,将对应的赫夫曼编码写入另一个文件(即加密的文件),所以,如果用户代开加密的文件即看到里面全是二进制代码,并不能分析出里面究竟是什么内容。
(至此,加密的文件应经生成)。
最后,因为每个文件中的内容不同,所以每个文件的赫夫曼编码也不同,而赫夫曼编码是根据字符的权重生成的,所以每个文件都对应一个字符权重系列(即密钥),如果失去这个密钥,即使对文件进行了加密,也不同解密文件的内容,即文件加密失效,所以在生成加密文件后,一定要导出文件的字符权重(即密钥),以待之后的解码使用。
(至此,文件的加密工作应经全部完成)。
4.2.文件解码(解密)
文件的解码程序是一步完成的,即要求操作者首先将之前生成的字符权重(即密钥)导入程序,程序根据获取到得字符权重,调用赫夫曼编码子程序,进行赫夫曼编码。
然后程序会提示操作者将加密后的文件导入程序中,程序会根据在程序中获取到的二进制编码与赫夫曼编码进行对照识别,显示出对应的字符,因此,文件的解密工作完成。
5.详细设计
5.1.程序主体结构
程序主体结构分为文件编码与文件解码两个子程序。
文件编码后分别导出编码后文件与文件密钥。
文件解码需导入编码文件与文件密钥,然后显示文本内容。
5.2.主要算法说明
5.2.1.Huffman树
//HuffmanTreelist:
list为赫夫曼树.
typedefstruct
{
chardata;//存放字符数据
intweight;//存放字符权重
intparent,lchild,rchild;//分别为根、左子树、右子树
}HuffmanTree;
//Staticinfo:
info为存放字符权重的数组指针.
typedefstruct
{
chardata;//存放字符数据
intweight;//存放字符权重
}Static;
//intcodeSize:
codeSize为字符种类个数.
voidCreatHuffmanTree(HuffmanTree*&list,Static*info,intcodeSize)
{
inti,j,limit;
intlnode,rnode;
intvalue1,value2;
HuffmanTree*ptr;
limit=codeSize*2-1;//limit为赫夫曼树结点个数
if((list=(HuffmanTree*)malloc(sizeof(HuffmanTree)*limit))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
/*******************初始化赫夫曼树各结点信息**************************/
for(i=0,ptr=list;i{
ptr->data=info[i].data;
ptr->weight=info[i].weight;
ptr->parent=ptr->lchild=ptr->rchild=-1;
}
for(;i{
ptr->data='0';
ptr->weight=0;
ptr->parent=ptr->lchild=ptr->rchild=-1;
}
/***********************开始建立赫夫曼树******************************/
for(i=codeSize;i{
value1=value2=32767;
lnode=rnode=-1;
//此部分函数功能为选择权值最小的两个结点
for(j=0;j
{
if(list[j].parent==-1)
{
if(list[j].weight{
value2=value1;
rnode=lnode;
value1=list[j].weight;
lnode=j;
}
elseif(list[j].weight{
value2=list[j].weight;
rnode=j;
}
}
}
//此部分函数功能为选择出的结点建立关系
list[lnode].parent=i;
list[rnode].parent=i;
list[i].weight=list[lnode].weight+list[rnode].weight;
list[i].lchild=lnode;
list[i].rchild=rnode;
}
}
5.2.2.Huffman编码
voidCreatHuffmanCode(HuffmanTree*list,HuffmanCode&code,intcodeSize)
{
inti,start;
intflag1,flag2;
char*tempCode;
if((code=(char**)malloc(sizeof(char*)*codeSize))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
if((tempCode=(char*)malloc(sizeof(char)*codeSize))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
tempCode[codeSize-1]='\0';
/**************************从叶子结点到根结点逆向求编码***********************/
for(i=0;i{
start=codeSize-1;
for(flag1=i,flag2=list[i].parent;flag2!
=-1;flag1=flag2,flag2=list[flag2].parent)
{
if(list[flag2].lchild==flag1)
{
tempCode[--start]='0';
}
else
{
tempCode[--start]='1';
}
}
if((code[i]=(char*)malloc(sizeof(char)*(codeSize-start)))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
strcpy(code[i],&tempCode[start]);
}
free(tempCode);
}
5.2.3.字符权重计算
//DatacharacterList:
characterList为动态建立的存放字符种类及在文本中出现次数的单链表.
typedefstructnode
{
chardata;//存放字符数据
intnumber;//存放字符个数
structnode*next;
}Data;
//此算法中设计导入文件操作.
voidDataCount(Static*&info)
{
FILE*fp;
charch;
charchoice;
intcharacterNumber,typeNumber;
DatacharacterList;
Data*ptr,*current,*previous;
system("CLS");
printf("\n请输入需要打开的文件名称:
");
fflush(stdin);
gets(fileName);
while((fp=fopen(fileName,"rb"))==NULL)
{
printf("\n您需要打开的文件不存在,是否需要重新打开(Y/N)?
:
");
fflush(stdin);
choice=getchar();
switch(choice)
{
case'Y':
system("CLS");
printf("\n请输入需要打开的文件名称:
");
fflush(stdin);
gets(fileName);
continue;
case'N':
return;
default:
break;
}
}
characterNumber=typeNumber=0;
characterList.next=NULL;
//从文件中读取信息并统计
while((ch=fgetc(fp))!
=EOF)
{
current=characterList.next;
if(current==NULL)
{
if((ptr=(Data*)malloc(sizeof(Data)))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
ptr->data=ch;
ptr->number=1;
ptr->next=characterList.next;
characterList.next=ptr;
++typeNumber;
}
else
{
while((current!
=NULL)&&(current->data!
=ch))
{
previous=current;
current=current->next;
}
if(current!
=NULL)
{
++(current->number);
++characterNumber;
}
else
{
if((ptr=(Data*)malloc(sizeof(Data)))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
ptr->data=ch;
ptr->number=1;
ptr->next=current;
previous->next=ptr;
++typeNumber;
++characterNumber;
}
}
}
fclose(fp);
codeSize=typeNumber;
info=(Static*)malloc(sizeof(Static)*codeSize);
current=characterList.next;
//将统计好的字符权重信息存入权重文件中
for(inti=0;i{
info[i].data=current->data;
info[i].weight=(int)(current->number*100.0/characterNumber);
current=current->next;
}
}
5.2.4.字符解码
//此代码用于比较查找赫夫曼编码
boolCompareData(char*tempCode,int&position)
{
for(position=0;position{
if(strcmp(tempCode,code[position])==0)
{
returntrue;
}
}
returnfalse;
}
voidDisplayContext()
{
InportCharacterWeight();
CreatHuffmanTree(list,info,codeSize);
CreatHuffmanCode(list,code,codeSize);
InportFileCoding();
FILE*fp;
intposition;
intend;
char*tempCode;
charch;
fp=fopen(fileName,"rb");
if((tempCode=(char*)malloc(sizeof(char)*codeSize))==NULL)
{
printf("内存不足,操作失败!
\n");
exit(0);
}
end=0;
/******************************此部分为解码过程************************/
printf("\n文件内容为:
\n\n");
while((ch=fgetc(fp))!
=EOF)
{
tempCode[end]=ch;
++end;
tempCode[end]='\0';
if(CompareData(tempCode,position))
{
printf("%c",info[position].data);
end=0;
}
}
printf("\n\n按任意键结束!
");
getch();
}
6.实验结果
6.1.实验结果说明
经过多次对本程序的实验,此次编译完成的程序可以对简单的文本文件进行加密和解密,因为限于对文件的基本操作不是太完全清楚,只是匆匆查阅了一些关于C语言文件操作部分的资料,所以这也是文件操作方面的一个瑕疵。
所以综上,次此的程序只能进行简单的加密与解密操作。
6.2.程序运行截图
(图1:
赫夫曼加密程序主体窗口)
(图2:
赫夫曼文件编码程序窗口)
(图3:
用于测试的文本原始文本内内容)
(图4:
导出文件编码后,在创建的编码文件中生成的二进制数)
(图5:
导出的文本密钥(即字符权重))
(图6:
赫夫曼文件译码程序窗口)
(图7:
将之前生成的编码文件与密钥导入进来后显示出原来的文本内容)
7.设计体会
进过此次的实验,让我对树结构及最优二叉树概念与操作的理解。
在此次选择赫夫曼编码操作的时候,本打算用赫夫曼编码的程序对文件进行压缩存储,可是限于不知道怎样将生成的赫夫曼编码进行bit级别的存储(只知道进行Byte级别的存储),所以压缩存储的想法失败了,之后根据赫夫曼编码的结构及生成的文件,不得不让我想到了文件的加密与解密,于是按着这个思路来设计了本文件加密解密系统。
在设计的时候,曾准备根据网上之前对26个英文字符的使用统计来事先对字符权重进行分配(这样加密的文件可解密性增加了),而且考虑到文件中不仅有26个英文字母,如果对各种字符的使用频率进行统计,这个事先工作的负担会很重,所以之后编写了自动统计文本字符的频率程序,这样工作量会减小很多(而且文件的可解密性大大减小,但是也带来了记录密钥的不方便)。
总体感觉程序还行,就是代码的简洁性还是有点差,条理还是不那么清晰。
8.参考文献
[1]严蔚敏、吴伟明.数据结构.清华大学出版社.1997.4
[2]ThomasH.Cormen、CharlesE.Leiserson.算法导论.机械工业出版社.2006.9
9.附:
程序代码
#include
#include
#include
#include
//赫夫曼树结构
typedefstruct
{
chardata;
intweight;
intparent,lchild,rchild;
}HuffmanTree;
//字符权重结构
typedefstruct
{
chardata;
intweight;
}Static;
//统计字符时所用到的链表结构
typedefstructnode
{
chardata;
intnumber;
structnode*next;
}Data;
//赫夫曼代码结构
typedefchar**HuffmanCode;
//创建赫夫曼树
voidCreatHuffmanTree(HuffmanTree*&list,Static*info,intcodeSize);
//创建赫夫曼代码
voidCreatHuffmanCode(HuffmanTree*list,HuffmanCode&code,intcodeSize);
//从文件中读取数据并计算各字符出现频率
voidDataCount(Static*&info);
//文件编码程序
voidFileEncoding();
//创建文件编码
voidCreatFileCoding();
//导出编码后文件
voidExportFileEncoding(HuffmanTree*list,HuffmanCodecode,intcodeSize);
//导出文件中字符权重
voidExportCharacterWeight();
//文件译码程序
voidFileDecoding();
//导入编码后的文件
voidInportFileCoding();
//导入文件中字符权重
voidInportCharacterWeight();
//显示译码后的文件内容
voidDisplayContext();
boolCompareData(char*tempCode,int&position);
voidBound(charcharacter,intsize);
//赫夫曼树
HuffmanTree*list;
//赫夫曼代码
HuffmanCodecode;
//字符权重信息
Static*info;
//字符种数
intcodeSize;
//文件名
charfileName[30];
intmain()
{
charchoice;
while(true)
{
system("CLS");
printf("赫夫曼编码加密程序\n");
Bound('-',25);
printf("1.文件编码\n");
printf("2.文件译码\n");
printf("0.退出程序\n");
Bound('-',25);
printf("请选择:
");
fflush(stdin);
choice=getchar();
switch(choice)
{
case'1':
FileEncoding();
break;
case'2':
FileDecoding();
break;
case'0':
printf("\n");
system("PAUSE");
return0;
break;
default:
printf("\n您的输入有误,按任意键后请从新输入!
");
getch();
break;
}
}
}
voidCreatHuffmanTree(HuffmanTree*&list,Static*info,intcodeSize)
{
inti,j,limit;
intlnode,rnode;
intvalue1,value2;
HuffmanTree*ptr;
limit=codeSize*2-1;
if((l