單詞(詞組)檢索算法
如今有一個英文字典(每一個單詞都是由小寫的'a'-'z'組成) ,單詞量很大,達到 100 多萬的單詞,並且還有不少重複的單詞。數組
此外,咱們如今還有一些 Document,每一個 Document 包含一些英語單詞。數據結構
針對這個問題,請你選擇合適的數據結構,組織這些數據,使時間複雜度和空間複雜度測試
儘量低,而且解決下面的問題和分析本身算法的時間複雜度。ui
1)基本型問題spa
(1)選擇合適的數據結構,將全部的英文單詞生成一個字典 Dictionary。指針
(2)給定一個單詞,判斷這個單詞是否在字典 Dictionary中。若是在單詞庫中,輸出這個單詞總共出現的次數。不然輸出 NO擴展:code
2)擴展型問題blog
(3)給定一個單詞,按字典序輸出字典 Dictionary 中全部以這個單詞爲前綴的單詞。例如,若是字典 T={a,aa, aaa, b, ba}, 若是你輸入 a,那麼輸出應該爲{a, aa, aaa}。遞歸
(4)給定一個單詞,輸出在Dictionary 中以這個單詞爲前綴的單詞的出現頻率最高的10個單詞,對於具備相同出現次數的狀況,按照最近(即最後)插入的單詞優先級比較高的原則輸出。
(5)輸出 Dictionary 中出現次數最高的 10個單詞。
程序所能達到的功能:
(1)創建字典樹
(1)查找給定單詞的出現頻率
(3)輸出以給定單詞爲前綴的全部單詞
(4)及其中頻率最高的十個單詞
(5)所有單詞裏頻率最高的十個單詞
//一下圈記的都是得事先存入工程文件夾的tex文檔
#include<stdio.h> #include<string.h> #include<malloc.h> #include<time.h> FILE *out;//設置全局變量,用於遞歸程序 FILE *f2; long num2=1; struct TrieNode { char c; char word[50]; struct TrieNode *next[26]; long count; }; typedef struct { char pl[50]; long mount; }PINLV; typedef PINLV pinlv[10]; pinlv b;//設置全局變量,用於遞歸程序 void chushihua(TrieNode *&p) { int i; (*p).c='#'; for(i=0;i<50;i++) p->word[i]='\0'; //strcpy(p->word,"root"); for(i=0;i<26;i++) p->next[i]=NULL; p->count=0; } //創建字典樹 struct TrieNode* JLTrieNode(TrieNode *root,char s[50]) { int i,j; struct TrieNode *q,*p; q=root; for(i=0;s[i]!='\0';i++) { if(q->next[s[i]-'a']!=NULL) q=q->next[s[i]-'a']; else { p=(struct TrieNode *)malloc(sizeof(struct TrieNode)); q->next[s[i]-'a']=p; p->c=s[i]; p->count=0;//初始化節點值 for(j=0;j<50;j++) p->word[j]='\0'; for(j=0;j<26;j++) p->next[j]=NULL; q=q->next[s[i]-'a']; } } q->count++; strcpy(q->word,s); return root; } //(3)輸出以單詞***爲前綴的全部單詞**************3333333333333333333333 void digui3(struct TrieNode *q) { int i; struct TrieNode *p; for(i=0;i<26;i++) { p=q->next[i]; if(p!=NULL) { if((*p).count!=0) //*********** { //printf("%s ",(*p).word); //(若q爲根節點,則能夠用於遍歷整個字典樹) fprintf(f2,"%s\n",(*p).word); } digui3(p); } } } //(4,5)遞歸遍歷,得到頻率最高的單詞*********3333333333333333333333 void digui5(struct TrieNode *q, pinlv &a) { int i,j,k; struct TrieNode *p; for(i=0;i<26;i++) { p=q->next[i]; if(p!=NULL) { if((*p).count!=0) //*********** { //*****將頻率最高的10個單詞記錄在a[j].pl中********444444444444444444444444*/ for(j=0;j<10;j++) { if((*p).count>=a[j].mount) { for(k=9;k>=j+1;k--) { strcpy(a[k].pl,a[k-1].pl); a[k].mount=a[k-1].mount; } strcpy(a[j].pl,(*p).word); a[j].mount=(*p).count; break; } } //********4444444444444444444444444444*555555555555555555555555********/ } digui5(p,a); } } } //查找單詞的出現次數(頻率) void chazhao2(struct TrieNode *root,char str[50]) { int i,j; struct TrieNode *q; q=root; for(i=0;str[i]!='\0';i++)//根據str在樹中搜索:是否存在這個單詞 { if(q->next[str[i]-'a']!=NULL) q=q->next[str[i]-'a']; else { fprintf(f2,"CASE %d:\nNO\n",num2); break; } //若是單詞還未遍歷結束(str[i]!='\0'),就指向了NULL,說明該單詞不在「文檔」中(即不在字典樹中) } if(str[i]=='\0') { if(q->count!=0) fprintf(f2,"CASE %d:\n%d\n",num2,q->count); else fprintf(f2,"CASE %d:\nNO\n",num2); } } //(第3問)**輸出以單詞str[]爲前綴的單詞********* void chazhao3(struct TrieNode *root,char str[50]) { int i,j; struct TrieNode *q; q=root; for(i=0;str[i]!='\0';i++)//根據str在樹中搜索:是否存在這個單詞 { if(q->next[str[i]-'a']!=NULL) q=q->next[str[i]-'a']; else { break; } //若是單詞還未遍歷結束(str[i]!='\0'),就指向了NULL,說明該單詞不在「文檔」中(即不在字典樹中) } if(str[i]=='\0') { //printf("文檔中以單詞%s爲前綴的單詞有:\n",str); if(q->count!=0) fprintf(f2,"%s\n",(*q).word); digui3(q);//(3,4問)在遞歸程序中輸出以單詞str[]爲前綴的全部單詞,而且記錄以單詞str爲前綴的頻率最高的10個單詞爲單詞於pinlv a中 } } //(第4問)輸出以單詞str爲前綴的頻率最高的10個單詞爲單詞****************************************/ void chazhao4(struct TrieNode *root,char str[50]) { int i,j; pinlv a;//(第4問)************************** for(i=0;i<10;i++)//對字符數組pinlv a進行初始化(pinlv a中存放以***爲前綴的頻率最高的10個單詞) { for(j=0;j<50;j++) a[i].pl[j]='\0'; a[i].mount=0; } struct TrieNode *q; q=root; for(i=0;str[i]!='\0';i++)//根據str在樹中搜索:是否存在這個單詞 { if(q->next[str[i]-'a']!=NULL) q=q->next[str[i]-'a']; else break; //若是單詞還未遍歷結束(str[i]!='\0'),就指向了NULL,說明該單詞不在「文檔」中(即不在字典樹中) } if(str[i]=='\0') { strcpy(a[0].pl,(*q).word); a[0].mount=(*q).count; digui5(q,a);//在遞歸程序中輸出以單詞str[]爲前綴的全部單詞,而且記錄以單詞str爲前綴的頻率最高的10個單詞爲單詞於pinlv a中 //printf("\n以單詞%s爲前綴的頻率最高的10個單詞爲單詞:\n",str); for(i=0;i<10;i++) { if(a[i].mount!=0) { fprintf(f2,"%s ",a[i].pl); fprintf(f2,"%d\n",a[i].mount); } } } } int main() { int i,k; FILE *fp; /***********************測試建樹的時間***********************************/ double duration; clock_t start= clock();//******運行時間測試開始 //(第1問)創建字典樹 struct TrieNode *root; char s[50]={'\0'}; fp=fopen("vocabulary.txt","r"); root=(struct TrieNode *)malloc(sizeof(struct TrieNode)); chushihua(root);//初始化頭結點指針 while(!feof(fp))//從文檔中換行讀取數據 { fscanf(fp,"%s",s); root=JLTrieNode(root,s); }; fclose(fp); clock_t finish = clock();//*****運行時間測試結束 duration = (double)(finish-start);//CLOCKS_PER_SEC; printf( "建樹時間爲: %5.3f ms\n",duration ); /**************************************************************************/ //(第2問)單詞***的個數 char str[50]={'\0'};//存放要查找的單詞 fp=fopen("(2)SearchWordInVocabulary.txt","r"); f2= fopen("(2)SearchWordInVocabulary_Result.txt","w"); while(!feof(fp))//從文檔中換行讀取數據 { fscanf(fp,"%s",str); chazhao2(root,str); for(i=0;i<50;i++) str[i]='\0'; num2++; }; fclose(fp); fclose(f2); num2=1; //(第3問)以單詞***爲前綴的全部單詞 fp=fopen("(3)TotPrefixWord.txt","r"); f2= fopen("(3)TotPrefixWord_Result.txt","w"); while(!feof(fp))//從文檔中換行讀取數據 { fscanf(fp,"%s",str); if(str[0]!='\0') { fprintf(f2,"CASE %d:\n",num2); chazhao3(root,str); } for(i=0;i<50;i++) str[i]='\0'; num2++; } fclose(fp); fclose(f2); num2=1; //(第4問)以單詞***爲前綴的單詞的出現頻率最高的10個單詞 fp=fopen("(4)PrefixFrequence.txt","r"); f2= fopen("(4)PrefixFrequence_Result.txt","w"); while(!feof(fp))//從文檔中換行讀取數據 { fscanf(fp,"%s",str); if(str[0]!='\0') { fprintf(f2,"CASE %d:\n",num2); chazhao4(root,str); } for(i=0;i<50;i++) str[i]='\0'; num2++; } fclose(fp); fclose(f2); num2=1; //(第5問)在遞歸算法中將頻率最高的10個單詞記錄在b[j].pl中 for(i=0;i<10;i++)//對字符數組pinlv b進行初始化(pinlv b 存放頻率最高的十個單詞及其頻率) { for(k=0;k<50;k++) b[i].pl[k]='\0'; b[i].mount=0; } digui5(root,b); //輸出所有單詞中頻率最高的10個單詞到文件中 fp=fopen("(5)MostFrequenceWord.txt","w"); for(i=0;i<10;i++) //fprintf(fp,"(%d)%-10s %d\n",i,b[i].pl,b[i].mount); fprintf(fp,"%s %d\n",b[i].pl,b[i].mount); fclose(fp); return 0; }