大魔王程式設計師生成記#專案01#統計文章中單次出現的個數,並排序
阿新 • • 發佈:2018-12-20
以下是第一次寫的程式碼:
#include<stdio.h> #include<assert.h> #include<malloc.h> #include<string.h> #include<ctype.h> #define SIZE 5000000 typedef struct Word { char arr[40]; int count;//當前單詞個數 }Word;//儲存每個單詞 typedef struct Num { Word *brr;//指向某一個單詞的結構體 int length; int listsize; }N;//單詞總量 const char* GetWord(const char *path)//將檔案儲存在記憶體中 { assert(path!=NULL); FILE *fr=fopen(path,"r"); assert(fr!=NULL); fseek(fr,0,SEEK_END); int len=ftell(fr);//該函式返回位置識別符號的當前值。 char *str=(char *)malloc(len*sizeof(char)); fseek(fr,0,SEEK_SET);//重置 fread(str,len,1,fr); *(str+len-1)='\0'; fclose(fr); return str; } int Length(Num num)//統計總單詞個數 { return num.length; } Num WriteWords(const char*str,Num num)//將記憶體中的單詞寫入結構體 { assert(*str!=NULL); int i=0; int j=0; bool flag=false; while(*str!='\0') { if((*str>=65&&*str<=90)||(*str>=97&&*str<=122)||*str=='\'') { num.brr[i].arr[j]=*str; j++; str++; flag=true; } else { if(flag) { num.brr[i].count=1; num.brr[i].arr[j]='\0'; i++; num.length++; j=0; flag=false; } str++; } } return num; } Num SumWords(Num num,int many)//統計單詞出現個數 { for(int i=0;i,i<many;i++) { for(int j=i+1;j<many;j++) { if(num.brr[i].count==0) { break; } if(!strcmp(num.brr[i].arr,num.brr[j].arr)) { num.brr[i].count++; num.brr[j].count=0; } } } return num; } void Show(Num num,int many) { for(int i=0;i<many;i++) { if(num.brr[i].count==0) { continue; } printf("%s",num.brr[i].arr); printf(" %d\n",num.brr[i].count); } } Num Sort(Num num,int many)//排序 { /*int temp; char temp2[40];*/ Word temp; for(int j=0;j<many;j++) { for(int i=0;i<many-j;i++) { if(num.brr[i].count<num.brr[i+1].count) { temp=num.brr[i]; num.brr[i]=num.brr[i+1]; num.brr[i+1]=temp; /*temp=num.brr[i].count; strcpy(temp2,num.brr[i].arr); num.brr[i].count=num.brr[i+1].count; strcpy(num.brr[i].arr,num.brr[i+1].arr); num.brr[i+1].count=temp; strcpy(num.brr[i+1].arr,temp2); */ } } } return num; } int main() { const char *path="E:\\1.txt"; const char *str=GetWord(path); Num num; num.length=0; num.brr=(Word*)malloc(SIZE*sizeof(Word)); num = WriteWords(str,num); int many=Length(num); SumWords(num,many); Sort(num,many); Show(num,many); printf("總單詞個數為:%d\n",many); free(num.brr); return 0; }
注:所使用的文章是哈利波特與魔法石全文。vs2012,使用過程中isalpha這一類庫函式不知為何不能使用,所以判斷時用了一個類似的。
在這個版本中是存在BUG的,雖然能夠執行出結果,但是和答案有200左右的偏差,最高頻率出現的單詞個數也有5-10個左右的偏差。起初的原因,以為是在記憶體申請的時候不能夠在主函式返回正確的大小導致,於是就改變成不在函式中申請記憶體返回,而是選擇在主函式中申請。 但是執行的結果還是不行,沒有改變。於是又從文章中選取部分進行測試,通過斷點監視,一步步來尋找出錯點。於是發現在從檔案寫入記憶體時,我是用的檔案讀取是fread(str,len,1,fr);是一次性全部讀取。我測試過檔案的長度,返回值是正確的,那麼理論上應該是能夠一次性把檔案的內容寫到記憶體中,但是通過監視視窗發現,在文章快要到結束的時候,後面的文字沒有被寫入記憶體,全部都是“屯屯屯”。然後又試了各種方式,但無果。最終只好放棄這種方式,改為使用fgetc()進行逐字寫入。以下是最終版:(程式中有很多註釋掉的地方,都是之前的測試)
#include<stdio.h> #include<assert.h> #include<malloc.h> #include<string.h> #include<ctype.h> #include <time.h> #define SIZE 5000000 /* “燙”是未初始化的棧空間,“屯”是申請後未做過記憶體清零或COPY的堆記憶體。 */ typedef struct Word { char arr[40]; int count;//當前單詞個數 }Word;//儲存每個單詞 typedef struct Num { Word *brr;//指向某一個單詞的結構體 int length; int listsize; }N;//單詞總量 int Len(const char *path) { assert(path!=NULL); FILE *fr=fopen(path,"r"); assert(fr!=NULL); fseek(fr,0,SEEK_END); int len=ftell(fr); fclose(fr); return len; } char* GetWord(const char *path,char *str,int len)//將檔案儲存在記憶體中 { //assert(path!=NULL); FILE *fr=fopen(path,"r"); //assert(fr!=NULL); //fseek(fr,0,SEEK_END); //int len=ftell(fr);//該函式返回位置識別符號的當前值。 //char *str=(char *)malloc(len*sizeof(char)); //fseek(fr,0,SEEK_SET);//重置 //fread(str,len,1,fr); //*(str+len+1)='\0'; fseek(fr,0,SEEK_SET); for(int i=0;i<len;i++) { *str=fgetc(fr); //printf("%c",*str); str++; } /*do { *str=fgetc(fr); printf("%c",*str); str++; } while(*str!=EOF);*/ //str++; *str='\0'; fclose(fr); return str; } int Length(Num num)//統計總單詞個數 { return num.length; } Num WriteWords(const char*str,Num num)//將記憶體中的單詞寫入結構體 { assert(*str!=NULL); int i=0; int j=0; bool flag=false; while(*str!='\0') { if((*str>=65&&*str<=90)||(*str>=97&&*str<=122)||*str=='\'') { num.brr[i].arr[j]=*str; j++; str++; flag=true; } else { if(flag) { num.brr[i].count=1; num.brr[i].arr[j]='\0'; i++; num.length++; j=0; flag=false; } str++; } } return num; } Num SumWords(Num num,int many)//統計單詞出現個數 { for(int i=0;i,i<many;i++) { for(int j=i+1;j<many;j++) { if(num.brr[i].count==0) { break; } if(!strcmp(num.brr[i].arr,num.brr[j].arr)) { num.brr[i].count++; num.brr[j].count=0; } } } return num; } void Show(Num num,int many) { for(int i=0;i<many;i++) { if(num.brr[i].count==0) { continue; } printf("%s",num.brr[i].arr); printf(" %d\n",num.brr[i].count); } } Num Sort(Num num,int many)//排序 { /*int temp; char temp2[40];*/ Word temp; for(int j=0;j<many;j++) { for(int i=0;i<many-j;i++) { if(num.brr[i].count<num.brr[i+1].count) { temp=num.brr[i]; num.brr[i]=num.brr[i+1]; num.brr[i+1]=temp; /*temp=num.brr[i].count; strcpy(temp2,num.brr[i].arr); num.brr[i].count=num.brr[i+1].count; strcpy(num.brr[i].arr,num.brr[i+1].arr); num.brr[i+1].count=temp; strcpy(num.brr[i+1].arr,temp2); */ } } } return num; } int main() { clock_t start,finish;//記錄程式執行時間 double totaltime; start=clock(); const char *path="E:\\1.txt"; //const char *str=GetWord(path); int len=Len(path); char *str=(char *)malloc(len*sizeof(char)); GetWord(path,str,len); Num num; num.length=0; num.brr=(Word*)malloc(SIZE*sizeof(Word)); num = WriteWords(str,num); int many=Length(num); SumWords(num,many); Sort(num,many); Show(num,many); printf("總單詞個數為:%d\n",many); free(num.brr); finish=clock();//記錄程式執行時間 totaltime=(double)(finish-start)/CLOCKS_PER_SEC; printf("\n程式執行的時間為: %.5f 秒",totaltime); return 0; }
這個版本的執行結果是沒有問題的。
在這個專案完成後,就要考慮程式的時間複雜度,來進行優化。這個專案將來還要進行許多的改進,比如說在排序方面,可以變為快排,堆排以減少時間複雜度。還可以往裡面加功能,如輸入字串進行查詢,顯示字串共出現的次數。