單詞(詞組)檢索算法
如今有一個英文字典(每一個單詞都是由小寫的'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;//設置全局變量,用於遞歸程序 static int pd=0;//遞歸搜索所有單詞中頻率最高的10個單詞爲單詞後,pd 仁然保持爲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'; 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; } long bianli(struct TrieNode *root)//遍歷字典樹並將單詞按字母表順序輸出 { int i; static long j=0,zonggong=0; struct TrieNode *p; for(i=0;i<26;i++) { p=root->next[i]; if(p!=NULL) { if((*p).count!=0) //*********** { if(j%2==0) fprintf(out,"\n"); //將全部排好序的單詞存於磁盤中 else fprintf(out," "); fprintf(out,"(%d)%-35s %-5d",j,(*p).word,(*p).count); //在窗口中輸出全部的已排好序的單詞 /*if(j%2==0) printf("\n"); else printf(" "); printf("(%d)%-20s ",j,(*p).word); printf("%-4d",(*p).count); */ zonggong+=(*p).count; j++; } zonggong=bianli(p); } } return zonggong; } void digui(struct TrieNode *q, pinlv &a) { int i,j,k; if((*q).c=='#') pd=1; struct TrieNode *p; j=0;/**********444444444444444444444444*/ for(i=0;i<26;i++) { p=q->next[i]; if(p!=NULL) { if((*p).count!=0) //*********** { if(pd!=1)//(3)輸出以單詞***爲前綴的全部單詞***3333333333333333333333 printf("%s ",(*p).word);//(若q爲根節點,則能夠用於遍歷整個字典樹) //*****將頻率最高的10個單詞記錄在a[j].pl中********444444444444*/ 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************************/ } digui(p,a); } } } void chazhao(struct TrieNode *root,char str[50]) { int i,j,pan=0; 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 { printf("沒有這個單詞\n"); break;}//若是單詞還未遍歷結束(str[i]!='\0'), //就指向了NULL,說明該單詞不在「文檔」中(即不在字典樹中) } if(str[i]=='\0') { printf("文檔中單詞%s共有%d個\n",str,q->count);//(第2問)**輸出以單詞str[]的個數 printf("文檔中以單詞%s爲前綴的單詞有:\n",str);//(第3問)**輸出以單詞str[]爲前綴的單詞 digui(q,a);//(3,4問)在遞歸程序中輸出以單詞str[]爲前綴的全部單詞, //而且記錄以單詞str爲前綴的頻率最高的10個單詞爲單詞於pinlv a中 //(第4問)輸出以單詞str爲前綴的頻率最高的10個單詞爲單詞********************/ if(a[0].mount==0) printf("!!!沒有以單詞%s爲前綴的單詞 ",str); else { printf("\n以單詞%s爲前綴的頻率最高的10個單詞爲單詞:\n",str); for(i=0;i<10;i++) { printf("(%d)%-10s ",i,a[i].pl); printf("%d\n",a[i].mount); } } //(第4問)輸出以單詞str爲前綴的頻率最高的10個單詞爲單詞*******************/ } } int main() { /***********************測試建樹的時間***********************************/ double duration; clock_t start= clock();//******運行時間測試開始 char s[50]={'\0'}; int i,k; struct TrieNode *root; FILE *fp; fp=fopen("文檔.txt","r"); root=(struct TrieNode *)malloc(sizeof(struct TrieNode)); chushihua(root);//初始化頭結點指針 while(!feof(fp))//從文檔中換行讀取數據 { fscanf(fp,"%s",s); root=JLTrieNode(root,s);//(第1問)創建字典樹 }; clock_t finish = clock();//*****運行時間測試結束 duration = (double)(finish-start);//CLOCKS_PER_SEC; printf( "建樹時間爲: %5.3f ms\n",duration ); fclose(fp); /**************************************************************************/ out=fopen("單詞排序.txt","w");//打開一個文檔,存放全部單詞的按字母排序 long zonggong; zonggong=bianli(root);//遍歷字典樹 printf("\n總共有%d個單詞\n",zonggong);//輸出總共的單詞個數 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; } //(第5問)在遞歸算法中將頻率最高的10個單詞記錄在b[j].pl中 digui(root,b); printf("所有單詞中頻率最高的10個單詞爲單詞:\n");//輸出所有單詞中頻率最高的10個單詞爲單詞 for(i=0;i<10;i++) { printf("(%d)%-10s ",i,b[i].pl); printf("%d\n",b[i].mount); } printf("\n"); pd=pd-1;//digui(root,b)後pd一直保持爲1 char panduan; char str[50]={'\0'};//存放要查找的單詞 panduan='y'; while(panduan=='y') { printf("請輸入要查找的單詞:"); scanf("%s",str); //(2,3,4問)輸出文檔中以***爲前綴的全部單詞,並輸出其中頻率最高的10個單詞 chazhao(root,str); printf("\n是否繼續?y/n:"); do { getchar(); panduan=getchar();//僅輸入一個字符,不容許多輸入 if(!(panduan=='y'||panduan=='n')) printf("輸入字符錯誤,請從新輸入(y/n)!"); }while( !((panduan=='y')||(panduan=='n')) ); } return 0; }