数据结构设计说明和代码.docx
《数据结构设计说明和代码.docx》由会员分享,可在线阅读,更多相关《数据结构设计说明和代码.docx(26页珍藏版)》请在冰豆网上搜索。
数据结构设计说明和代码
数据结构设计大赛作品说明书
作品名称:
译码器
院系:
计算机科学与信息工程学院
学生姓名:
李瑞琳
学号:
200903060016
专业班级:
09级网络工程
(二)班
指导教师:
闫怀平
年05月20日
一、作品的背景【说明设计该作品的目的,或者说作品能够解决什么实际问题】
目前,进行远距离快速通信的主要手段是电报,即将需传送的文字转换成由二进制的字符组成的字符串,并且让传送的文件中次数较多的字符采用尽可能短,以及译码后所得到的译码文件唯一。
另外,当今的密码学就是在编码与译码的斗争中发展起来的,成为一门综合行的尖端技术科学,为此,做了如下的具体算法实现。
1.解决的实际问题:
⑴读取要编码的文本文件,将文件的内容进行编码,生成新的文件。
⑵对编码文件进行解码,获得文本文件。
2.要求:
⑴将输入的文件进行编码,得到相应的密码序列。
⑵将译码的文本文件和原文件进行比较,恢复文件和原文件必须完全一致。
二、设计思路【说明为了解决实际的问题,采用什么样的数据和算法】
1.采用的数据如下:
设字符集及频度如下表:
字符
空格
A
B
C
D
E
F
G
H
I
J
K
L
M
频度
186
64
13
22
32
103
21
15
47
57
1
5
32
20
字符
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
频度
57
63
15
1
48
51
80
23
8
18
1
16
1
2.采用算法如下:
采用Huffman编码思想实现对字符串的编码,以及对编码的解码。
⑴对上述表格中的27个字符分别编码(为便于输入,‘空格’在程序实现过程中用‘*’代替),其实现算法是建立赫夫曼树HC,对每一个字符进行编码,并将由赫夫曼树所得到的编码串存储在HC中。
⑵建立编码、译码函数,对输入的文件或密码进行转换,再通过main()函数的调用,将其进行输出。
二、程序主要方法说明【说明主要方法的功能和实现细路以及技巧,只要方法的声明,不要贴实现代码】
㈠实现思路:
建立如图所示的赫夫曼树(赫弗曼树的形式不唯一),并编码
1000
1
0
0
603
397
1
1
0
211
186
355
248
空格
1
1
1
0
0
0
182
173
128
120
103
108
1
1
1
1
0
0
0
0
0
E
1
63
64
78
102
51
95
80
64
57
57
O
N
I
1
1
1
0
0
0
0
T
S
A
1
0
48
47
53
43
35
32
32
49
1
1
1
0
0
0
H
R
L
D
0
23
20
18
17
31
22
28
21
1
1
1
0
0
W
U
M
F
C
1
0
9
8
16
15
15
13
1
0
Y
V
P
G
B
5
4
1
1
0
0
K
2
2
1
1
1
1
Z
X
Q
J
HT初态:
HT终态:
HT
HT
weight
parent
lchild
rchild
weight
parent
lchild
rchild
1
186
0
0
0
1
186
51
0
0
2
64
0
0
0
2
64
45
0
0
3
13
0
0
0
3
13
33
0
0
4
22
0
0
0
4
22
38
0
0
5
32
0
0
0
5
32
39
0
0
6
103
0
0
0
6
103
48
0
0
7
21
0
0
0
7
21
37
0
0
8
15
0
0
0
8
15
33
0
0
9
47
0
0
0
9
47
41
0
0
10
57
0
0
0
10
57
43
0
0
11
1
0
0
0
11
1
28
0
0
12
5
0
0
0
12
5
31
0
0
13
32
0
0
0
13
32
39
0
0
14
20
0
0
0
14
20
36
0
0
15
57
0
0
0
15
57
44
0
0
16
63
0
0
0
16
63
44
0
0
17
15
0
0
0
17
15
34
0
0
18
1
0
0
0
18
1
28
0
0
19
48
0
0
0
19
48
41
0
0
20
51
0
0
0
20
51
43
0
0
21
80
0
0
0
21
80
47
0
0
22
23
0
0
0
22
23
36
0
0
23
8
0
0
0
23
8
32
0
0
24
18
0
0
0
24
18
35
0
0
25
1
0
0
0
25
1
29
0
0
26
16
0
0
0
26
16
34
0
0
27
1
0
0
0
27
1
29
0
0
28
0
0
0
28
2
30
11
18
29
0
0
0
29
2
30
25
27
30
0
0
0
30
4
31
28
29
31
0
0
0
31
9
32
30
12
32
0
0
0
32
17
35
23
31
33
0
0
0
33
28
37
3
8
34
0
0
0
34
31
38
17
26
35
0
0
0
35
35
40
32
24
36
0
0
0
36
43
40
14
22
37
0
0
0
37
49
42
7
33
38
0
0
0
38
53
42
4
34
39
0
0
0
39
64
45
5
13
40
0
0
0
40
78
46
35
36
41
0
0
0
41
95
46
9
19
42
0
0
0
42
102
47
37
38
43
0
0
0
43
108
48
20
10
44
0
0
0
44
120
49
15
16
45
0
0
0
45
128
49
2
39
46
0
0
0
46
173
50
40
41
47
0
0
0
47
182
50
21
42
48
0
0
0
48
211
51
6
43
49
0
0
0
49
248
52
44
45
50
0
0
0
50
355
52
46
47
51
0
0
0
51
397
53
1
48
52
0
0
0
52
603
53
49
50
53
0
0
0
53
1000
0
51
52
1001
110010
10111
11000011
1100001000
0111
1000
1111011
111100
010
10110
111110
1111010
11010
1111110
1010
00
00
HC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1100001001
1100001010
0110
1110
110011
1100000
110001
1111111
1100001011
11011
㈡具体算法如下所示:
1.赫夫曼树和赫夫曼编码的存储结构表示
typedefstruct{
intweight,parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
2.⑴定义全局变量:
用于存储需要编码的字符集数组node[29]
用于存储需要编码的文件数组str[MAX1]
用于存储密码文件的数组Nfile[MAX2]
⑵建立相应的实现函数:
用于建立赫夫曼树函数HuffmanCoding(&HT,&HC,*w,n)
实现建立赫夫曼树的选择函数Select(HT,k,&m1,&m2)
实现对文件编码的编码函数Decode(HC)
实现对密码译码的译码函数Coding(HT,HC)
对以上函数进行调用的主函数main()
⑶出错判断响应
A.当输入文本错误时,提出错误提醒printf("第%d个字符输入错误!
请重新输入:
",j+1);
B.当选择执行的选项出错时,提出错误提醒printf("输入错误,请重新输入");
三、程序测试说明【为了验证程序满足设计要求,需要给出适当的测试数据。
如输入什么数据,程序能够输出什么数据。
要求至少给出3组以上测试数据,并说明每组测试数据能够测试作品的什么功能】
程序中输入及输出数据的运行步骤如下所示:
步骤一:
编译并运行程序,按提示运行(例如,“按回车键,继续…”)已验证所得赫弗曼树及27个字符的编码是否与分析的一致结果如下:
步骤二:
输入选择0-2以外的数,如3,以测试出错相应功能:
当选择执行的选项出错时,程序给出错误提醒。
得出如下结果:
步骤三:
输入文本文件“ROME*WAS*NOT*BUILT*IN*A*DAY”,并在程序执行前将存储密码文件的数组初始化如下:
Nfile[MAX2]={1,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,
1,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,
1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,
1,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1}
测试译码的文本文件和原文件进行比较,恢复文件和原文件是否完全一致
步骤四:
输入文本文件“TiME*is*MonEY”,测试错误判断响应当输入文本错误时,提出错误提醒printf("第%d个字符输入错误!
请重新输入:
",j+1);
步骤五:
输入正式文本文件“THANK*YOU*FOU*YOUR*LETTER*CONVEYING*ON*MY*APPOINTMENT*I*WISH*YOU*SUCCESS*AND*FULFILLMENT*THE*YEARS*AHEAD”得出相应密码文件:
步骤六:
选择“0”,返回,结束程序。
程序代码:
#include
#include
#include
#defineMAX13000
#defineMAX2110
#defineOK1
#defineERROR0
typedefintStatus;
typedefstruct{
intweight,parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
charnode[29]="*ABCDEFGHIGKLMNOPQRSTUVWXYZ";//定义字符集
intn=27;//需要编码的字符总数
intm=2*n-1;//赫夫曼编码表HT的长度
intcount=0;//记录输入的密码数字的个数
charstr[MAX1];//定义存储需要编码的文件数组
intNfile[MAX2]={1,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,
1,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,
1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,
1,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1};//定义密码文件数组
voidSelect(HuffmanTreeHT,intk,int&m1,int&m2)
{
inti,min1,min2;
min1=min2=10000;//首先给它们赋一个最大的值,这个值大于所有可能的权值
m1=1,m2=1;
for(i=1;i<=k;i++)
if(HT[i].weight{min1=HT[i].weight;m2=m1;m1=i;}
elseif(HT[i].weight{min2=HT[i].weight;m2=i;}
}
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)
{//w存放n个字符的权值(均>0),构造赫夫曼树HT,
//并求出n个字符的赫夫曼编码HC
inti,j,s1,s2,start;
char*cd;
intc,f;
if(n<=1)return;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用
for(i=1;i<=n;i++){//初始化
HT[i].weight=w[i-1];
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=n+1;i<=m;i++){//初始化
HT[i].weight=0;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
printf("\n赫夫曼树的构造,初态如下所示:
\n");
printf("HT初态:
\n结点weightparentlchildrchild");
for(i=1;i<=m;i++)
printf("\n%6d%10d%10d%10d%10d",i,HT[i].weight,
HT[i].parent,HT[i].lchild,HT[i].rchild);
printf("按回车键,继续...");
getchar();
for(i=n+1;i<=m;i++){//建赫夫曼树
//在HT[1..i-1]中选择parent为0且weight最小的两个结点,
//其序号分别为s1和s2。
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("\n构造的赫夫曼树如下:
\n");
printf("结点weightparentlchildrchild");
for(j=1;j<=m;j++)
printf("\n%6d%10d%10d%10d%10d",j,HT[j].weight,
HT[j].parent,HT[j].lchild,HT[j].rchild);
printf("按回车键,继续...");
getchar();
//---从叶子到根逆向求每个字符的赫夫曼编码---
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;//编码结束符位置
for(c=i,f=HT[i].parent;f!
=0;c=f,f=HT[f].parent)
//从叶子到根逆向求编码
if(HT[f].lchild==c)cd[--start]='0';
elsecd[--start]='1';
HC[i]=(char*)malloc((n-start)*sizeof(char));
//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC
}
free(cd);//释放工作空间
//outputcoding
for(i=1;i<=n;i++)
printf("字符%c:
%s\n",node[i-1],HC[i]);
printf("\n");
}//HuffmanCoding
intDecode(HuffmanCodeHC){//编码
intj,L;
printf("请输入文本:
\n");
scanf("%s",str);getchar();
L=strlen(str);//求字符串的长度
printf("文本字符个数为:
");
printf("%d",L);
printf("\n");
for(j=0;jif(!
((str[j]>='A'&&str[j]<='Z')||(str[j]=='*')))
{
printf("第%d个字符输入错误!
请重新输入:
",j+1);
str[j]=getchar();getchar();
printf("\n");
}
printf("文本的编码如下:
\n");
j=0;
while(str[j]!
='\0')
{
for(inti=0;i<27;i++)
{
if(str[j]==node[i])
printf("%s",HC[i+1]);
}
j++;
}
printf("\n");
returnOK;
}
voidCoding(HuffmanTreeHT,HuffmanCodeHC){//译码
intj=0;
intt;
while(j{
t=m;
while(HT[t].lchild!
=0||HT[t].rchild!
=0)
{
if(Nfile[j]==0)
t=HT[t].lchild;
else
t=HT[t].rchild;
j++;
}
printf("%c",node[t-1]);
}
}
voidmain()
{
intk=1;
intn=27;
HuffmanTreeHT;
HuffmanCodeHC;
intw[]={186,64,13,22,32,103,21,15,47,57,1,5,32,20,
57,63,15,1,48,51,80,23,8,18,1,16,1};//各个需要编码字符的频度,即赫弗曼树结点的权值
HuffmanCoding(HT,HC,w,n);
while(k)
{
printf("\n");
printf("欢迎进入编码、译码系统\n");
printf("****************************\n");
printf("1.编码\n");
printf("2.译码\n");
printf("0.返回\n");
printf("****************************\n");
printf("请选择(0-2):
");
scanf("%d",&n);
getchar();
switch(n)
{
case1:
Decode(HC);break;
case2:
{
printf("密码文件如下:
\n");
for(inti=0;i{
printf("%d",Nfile[i]);
count++;
}
printf("\n");
printf("原文本如下:
\n");
Coding(HT,HC);
}break;
case0:
m=0;break;
default:
printf("输入错误,请重新输入");break;
}
}
}