1. 程式人生 > >大魔王程式設計師生成記#專案01#統計文章中單次出現的個數,並排序

大魔王程式設計師生成記#專案01#統計文章中單次出現的個數,並排序

 

 

 

以下是第一次寫的程式碼:

#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;
}

這個版本的執行結果是沒有問題的。

在這個專案完成後,就要考慮程式的時間複雜度,來進行優化。這個專案將來還要進行許多的改進,比如說在排序方面,可以變為快排,堆排以減少時間複雜度。還可以往裡面加功能,如輸入字串進行查詢,顯示字串共出現的次數。