数据结构课程设计实验报告.docx
《数据结构课程设计实验报告.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计实验报告.docx(13页珍藏版)》请在冰豆网上搜索。
数据结构课程设计实验报告
课程设计实验报告
班级:
10031101
学号:
2011302645
姓名:
王康
●题目:
单词(词组)检索
现在有一个英文字典(每个单词都是由小写的'a'-'z'组成),单词量很大,达到100多万的单词,而且还有很多重复的单词。
此外,我们现在还有一些Document,每个Document包含一些英语单词。
针对这个问题,请你选择合适的数据结构,组织这些数据,使时间复杂度和空间复杂度尽可能低,并且解决下面的问题和分析自己算法的时间复杂度。
1)基本型问题(必须采用字符串哈希,hash散列算法)
(1)将所有的英文单词生成一个字典Dictionary。
(2)给定一个单词,判断这个单词是否在字典Dictionary中。
如果在单词库中,输出这个单词总共出现的次数。
否则输出NO。
(3)输出Dictionary中出现次数最高的10个单词。
(必须采用快速排序或堆排序算法)
2)扩展型问题(可选择合适的数据结构)
(4)给定一个单词,按字典序输出字典Dictionary中所有以这个单词为前缀的单词。
例如,如果字典T={a,aa,aaa,b,ba},如果你输入a,那么输出应该为{a,aa,aaa}。
(5)给定一个单词,输出在Dictionary中以这个单词为前缀的单词的出现频率最高的10个单词,对于具有相同出现次数的情况,按照最近(即最后)插入的单词优先级比较高的原则输出。
对于以下问题,需采用2种不同的数据结构(hash散列与Trie树,并针对以下题目,比较两种数据结构的优缺点。
)
3)高级型问题
(6)现在我们有一些Document,每个Document由一些单词组成,现在的问题就是给你一个word,检索出哪些Document包含这个word,输出这些Document的DocumentID(就如同搜索引擎一样,即输入一些关键字,然后检索出和这些关键字相关的文档)。
(7)在第(6)问中,我们只考虑了一个word在哪些Document中的情况,我们进一步考虑2个相邻word的情况,检索出同时包含这两个相邻word的DocumentID。
4)挑战型问题
(8)现在我们再对(7)的问题进行扩展,把(7)中的只检索相邻2个word推广到可以检索多个word(即连续的k个word,其中k>=2),检索出同时包含k个连续word的DocumentID。
●
一、需求分析
本演示程序中,Vocabulary文件夹下的vocabulary.txt是英文字典的数据总共有120多万个单词,由此生成一个字典树。
SearchWordInVocabulay文件夹下对应的是问题
(2)中的数据,其中SearchWordInVocabulary.txt是要在字典中检索的数据,需要生成一个SearchWordInVocabulary_Result.txt来保存检索的结果,其中结果的格式为对于每个输入的Word,首先输出CASEID:
ID表示这个Word是输入的第ID个WORD,然后如果这个Word在字典中,输出这个Word出现的次数,否则输出“NO”。
TotPrefixWord文件夹下对应的是问题(3)中的数据,其中TotPrefixWord.txt是要在字典中检索的前缀的数据,需要生成一个TotPrefixWord_Result.txt文件来保存检索的结果,对于TotPrefixWord.txt中的一个输入prefix,输出格式同样是先输出CASEID:
,然后按字典序输出字典中以prefix为前缀的所有word(不能重复)。
PrefixFrequence文件夹下对应的是问题(4)中的数据,其中PrefixFrequence.txt是要在字典中检索的前缀的数据,需要生成一个PrefixFrequence_Result.txt文件来保存为检索的结果,对于PrefixFrequence.txt中的一个输入prefix,输出格式同样是先输出CASEID:
,然后按(4)中定义的优先级输出字典中优先级最高的10个以prefix为前缀word和这个word出现的次数,如果不足10个,就全部输出)。
对于问题(5),需要生成一个MostFrequenceWord.txt文件包含出现次数最多的10个单词和单词出现的次数。
2.演示程序以用户和计算机的对话方式执行,即在计算机终端上显示提示信息,告诉用户已完成那些题目。
3.程序执行的命令包括:
(1)构造哈希表;
(2)查找单词出现的次数;(3)找出前缀相同的单词并输出;(4)找出前缀相同出现次数最多的十个单词;(5)找出字典中出现次数最多的十个单词;(6)结束。
4.测试数据
根据要求得出结果,由给的软件判断结果是否正确。
2、概要设计
本程序包括五个模块:
(1)主程序模块;
(2)构造哈希表模块;
(3)查找单词模块;
(4)查找前缀相同单词模块;
(5)查找前缀相同出现次数最高的十个单词模块;
(6)查找出现次数最多的十个单词模块;
(7)模块调用图:
主程序模块
构造哈希表模块
查找单词模块
查找前缀相同单词模块
查找前缀相同出现次数最高的十个单词模块
查找出现次数最多的十个单词模块
3、详细设计
1、数据结构定义
#include
#include
#include
#include
#defineMAX100000
//===========
typedefstruct{
char*Pword;//存储的单词地址
inttimes;//单词出现的次数
}Data,*PData;//存储结构体
DataDic[MAX];
typedefstruct{
char*Pword;
inttimes;
}RedType;
typedefstruct{
RedTypedatas[MAX];
longintlength;
}HeapType;
HeapTypeheaps;
typedefstructTrie_node_stru
{
intcount;//记录该处终结的单词个数
structTrie_node_stru*next[26];//指向各个子树的指针,下标0-25代表26字符
inttag;
}TrieNode,*Trie;
2、哈希表的创建
unsignedintELFHash(char*str)/*ELFHashFunction*/
{
unsignedinthash=0;
unsignedintx=0;
while(*str)
{
hash=(*str++)+(hash<<4);
if((x=hash&0xF0000000L)!
=0)
{
hash=hash^(x>>24);
hash=hash&(~x);
}
}
return((hash&0x7FFFFFFF)%39989);
}
voidCreatHT()
{
inti;
printf("初始化哈希表,请稍后...\n\n");
for(i=0;i{
Dic[i].times=0;
Dic[i].Pword=0;
}
printf("哈希表初始化完成\n");
}
intGetTimes(charch,inti)
{
if('\n'==ch||-1==ch)
returni+1;
else
returni;
}
3、哈希表的初始化和建立
intPush_hash(char*word,unsignedintpos)
{
inttag=0;
unsignedinti=pos;
intj=0;
if(Dic[pos].times==0)
{
Dic[pos].Pword=word;
Dic[pos].times++;
}
else
{
if(Dic[pos].times!
=0)
{
if(strcmp(Dic[pos].Pword,word)==0)
{
Dic[pos].times++;
tag=1;
}
else
{
pos=(pos+1)%MAX;
tag=Push_hash(word,pos);
}
}
}
returntag;
}
intRead()
{
FILE*fp;
charch=0;
unsignedintPOS=1;
inti=0/*单词的下标*/;
intTJ=0;
printf("\t开始构建哈希表...\n");
printf("\n请稍等……\n");
if(!
(fp=fopen("vocabulary.txt","r")))
{
printf("Cannotopenthefile...Creat_Hash_List\n");
exit(0);
}
while(!
(feof(fp)))
{
char*Inf,tmp[50]="";
intj=0;
Inf=Allwords+i;
do{
ch=fgetc(fp);
TJ=GetTimes(ch,TJ);
if(ch=='\n')
{
tmp[j]=Allwords[i]='\0';
}
else
{
tmp[j]=Allwords[i]=ch;
}
i++;
j++;
}while(ch!
='\n'&&!
feof(fp));
POS=ELFHash(tmp);
if(!
feof(fp))
{
if(Push_hash(Inf,POS))
{
i=Inf-Allwords;
}
}
else
{
if(-1==*Inf)
break;
Push_hash(Inf,POS);
break;
}
}//while
TJ--;
fclose(fp);
printf("\t哈希表构建over!
\n单词共有:
%7d个(重复计数)\n\n",TJ);。
return0;
}
longintNoRepetition()
{
inti;
longintj=0;
for(i=0;i{
if(Dic[i].times!
=0)
{
j++;
}
}
returnj;
}
4、创建字典
voidSearch_Hash()
{
chara[50];
chartag;
unsignedintposs;
printf("请输入您要搜索的单词:
");
gets(a);
poss=ELFHash(a);
if(!
strcmp(Dic[poss].Pword,a))
{
printf("查询到此单词!
共出现%7d次\n",Dic[poss].times);
}
else
{
while(Dic[poss].times&&strcmp(Dic[poss].Pword,a))
{
poss++;
}
if(!
Dic[poss].times)
printf("查无此词!
\n\n");
else
printf("查询到此单词!
共出现%7d次\n",Dic[poss].times);
}
printf("继续查询?
Y/N");
scanf("%c",&tag);
getchar();
if(tag=='Y'||tag=='y')
Search_Hash();
}
5、最热的10个单词的查找
voidstart_heap(longintlongs)
{
inti,j=1;
printf("初始化堆..\n");
for(i=0;i{
if(Dic[i].times)
{
heaps.datas[j].times=Dic[i].times;
heaps.datas[j].Pword=Dic[i].Pword;
j++;
}
}
heaps.length=longs;
printf("堆初始化完成\n");
}
voidHeapAdjust(HeapType&H,ints,intm){//算法10.10
//已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,
//本函数调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆
//(对其中记录的关键字而言)
intj;
RedTyperc;
rc=H.datas[s];
for(j=2*s;j<=m;j*=2){//沿key较大的孩子结点向下筛选
if(jif(rc.times>=H.datas[j].times)break;//rc应插入在位置s上
H.datas[s]=H.datas[j];s=j;
}
H.datas[s]=rc;//插入
}//HeapAdjust
voidHeapSort(HeapType&H){//算法10.11
//对顺序表H进行堆排序。
inti;
RedTypetemp;
for(i=H.length/2;i>0;--i)//把H.r[1..H.length]建成大顶堆
HeapAdjust(H,i,H.length);
for(i=H.length;i>1;--i){
temp=H.datas[i];
H.datas[i]=H.datas[1];
H.datas[1]=temp;//将堆顶记录和当前未经排序子序列Hr[1..i]中
//最后一个记录相互交换
HeapAdjust(H,1,i-1);//将H.r[1..i-1]重新调整为大顶堆
}
}//HeapSort
voidPrintFQ(HeapType&H,longinttotal)
{
FILE*out;
longinti;
if((out=fopen("MostFrequenceWord.txt","w"))==NULL)
{
printf("cannotopenfile\n");
exit(0);
}
for(i=total;i>total-10;i--)
{
fprintf(out,"%s\n%d\n",heaps.datas[i].Pword,heaps.datas[i].times);
}
}
四、程序使用说明及测试结果
1.程序使用说明
(1)本程序的运行环境为VC6.0
2.测试结果
根据所给的软件,测出所得文件正确
3.调试中的错误及解决办法(遇到时给出)
4.运行界面
由于文件内没有单词,暂时是这样。
五、实验总结
在这次程序的编写中,从来没有哪一次编程会用这么长的时间,刚开始就被题目的背景懵了,不知道从哪儿下手来写这个程序,后来一步步来,慢慢有了大体的框架,分布完成这个程序,首先花费了不少时间理解书上的算法,虽然有些挺难懂的,但是在空间和时间上都是很节约的算法。
指向结构体的指针和指向字符型数据的指针的指针在一定程度上比较难理解。
还有文件函数的应用很不熟悉,有些函数还是上网找的资料才会运用的,这次编程还有一个问题,就是自己虽然理解书本上的算法,可是自己不能独立写出来,这让我有点担心数据结构的考试,此次编程对我的启发是,以后要通过编程调试来做到对数据结构的深度了解。
只有通过实际编程,调试,找到错误,才能去改正它,才能做到真正的懂得。
这个程序的设计开始很不顺利,在实际编程过程中,许多问题都是我未曾预料到的,一些小的错误很难发现,得花大量的时间才能找到。
因此我觉得,只把教材中的东西理解是远远不行的,必须在不断地编程中锻炼对数据结构的理解与应用,也只有不断训练,才能真正提高自己的编程能力。
说实话,这两个星期对我的锻炼真的很大,我一直以为我的C语言学的还不错,这次课程设计不仅是对我编程能力极大的提高,更加增加了我对C语言的兴趣,最喜欢自己的程序编出来的那份喜悦。