统计文本中重复次数最多的前1000的单词,并按次数从高到低输出,并保存到另一个文本中

对于实现这个项目,我在做的过程中出现了许许多多的bug(本人十分小白),在这里我想在展示如何实现的过程中提出来,希望能帮助到和我一起学习的小伙伴!


在正式开始实现功能之前,我们需要定义两个结构体(个人做法,欢迎有其他做法的留言我们一起讨论进步);

	typedef struct Word
	{
		char word[20]; //存单词
		int count; //记录该单词出现的次数
	}Word; 

	typedef struct WordTable
	{
		Word *elem; //指向上面结构体的首地址
		int usedsize; //开辟的空间被使用的空间数
		int allsize; //开辟的总空间数
	}WordTable;

上面第二个结构体可能不好理解,可以对比下面这张图进行理解;(我们第一次开辟10个空间,实现代码下面介绍)
在这里插入图片描述


按照逻辑顺序,我们需要实现的是从下载的小说里读取单词;

void ReadWord(const char *path)
{
		FILE *fr=fopen(path,"r");//打开我们的小说文本
		assert(fr!=NULL);//断言打开成功
		char ch;//用来读取小说内的每一个字符
		int i=0;
		char newWord[20];//记录读取的字符
		bool flg=false;
		WordTable pwt;
		InitWordTable(&pwt);//初始化pwt,可以先不管,后面会有解释
		while(fread(&ch,sizeof(char),1,fr) > 0)
		{
			if(isalpha((unsigned char)ch))//字母字符是单词的一部分
			
			/*注意,我在做的时候 isalpha(ch)一直断言出错,原因是
			char类型的范围是 -128~127,而小说文本中可能有一些
			非法字符 例如NULL FF什么的,就会出现错误;
			只需要按上面这样进行判断就可以避免掉*/
			
			//if(isalpha((unsigned char)ch))
			{
				newWord[i++] = ch;//是英文字母,就保存到newWord的数组中
				flg = true;//将标记符赋位true
			}
			else //非字母字符
			{
				if(flg)//有新单词需要处理 //标记符被赋成true意味着数组里被英文字母填充过
				{
					//todo,
					newWord[i] = '\0';//置成字符串
					SaveWord(&wt,newWord);//将单词word保存到arr中,如果单词已经存在则其计数器++,不存在则添加
					//后面会讲
					flg = 0;//将flg再次置为false
					i = 0;//i初始化
				}
			}
		}		
fclose(fr);

下来我们实现上面出现的InitWordTable(&wt)
全局声明
#define INIT_SIZE 10

void InitWordTable(WordTable *pwt)
{
	assert(pwt!=NULL);
	pwt->elem=(Word *)malloc(sizeof(Word)*INIT_SIZE);//开辟10个Word结构体的空间大小,并让pwt->elem保存其首地址
	pwt->usedsize=0;//初始化使用过的空间数为0;
	pwt->allsize=INIT_SIZE;//开辟开辟的总空间数为10
}

下面实现SaveWord(&wt,newWord)

void SaveWord(WordTable *pwt,const char *newWord)
{
	int i = Search(pwt,newWord);//这里我们需要判断最新的单词,是否在我们的空间中有过记录,若出现过,返回值为-1,若没有出现过,返回下标
	if(i != -1)//该单词已经出现过
	{
		pwt->elem[i].count++;//直接将该下标中记录个数的count++
	}
	else//该单词是新单词,需要添加到pwt中
	{
		InsertWord(pwt,newWord);//插入函数,后面介绍
	}
}

实现Search(pwt,newWord)
在这一函数中我们判断newWord是否在之前记录过

int Search(WordTable *pwt,const char *newWord)
{
	for(int i=0;i<pwt->usedsize;i++)//注意我的循环条件,我们只需要在遍历 使用过的空间,其中记录着每一个不重复的单词
	{
		if(strcmp(pwt->elem[i].word,newWord)==0)//遍历时查找到同样的单词
		{
			return i;//直接返回下标,方便我们对其count进行++;
		}
	}
	return -1;//没有则返回-1
}

实现InsertWord(pwt,newWord);
插入函数,即当我们发现读的newWord在之前没有出现过,我们将其保存到已使用的空间的末尾。
而在我们保存单词的时候,需要判断使用过的空间是否已经满了,即需要用usedsize和allsize进行比较;

void InsertWord(WordTable *pwt,const char *newWord)
{
	if(pwt->allsize==pwt->usedsize)//此时没有空余空间了
	{
		pwt->allsize*=2;//直接将allsize*2;
		pwt->elem=(Word *)realloc(pwt->elem,pwt-	>allsize*sizeof(Word));//将已经开辟的空间同时扩大1倍
	}
	else//还存在可用的空间
	{
		strcpy(pwt->elem[pwt->usedsize].word,newWord);//将newWord直接copy到可用空间
		pwt->elem[pwt->usedsize].count=1;//并且将count置为1
		pwt->usedsize++;//将使用过的空间加1
	}
}

到这一步,我们就将读取单词的功能实现完成,接下来就是对其出现的次数进行排序,我使用了冒泡排序;

void BubbleSort(WordTable *pwt)
{
	int i,j;
	Word tmp; //空变量,用来做交换
	for(i=0;i<pwt->usedsize-1;i++)
	{
		for(j=i;j<pwt->usedsize-i;j++)
		{
			if(pwt->elem[j].count<pwt->elem[j+1].count)
			{
				tmp=pwt->elem[j];
				pwt->elem[j+1]=pwt->elem[j+1];
				pwt->elem[j+1]=tmp;
			}
		}
	}
}

好了排序也完成了,我们就需要将其写入另一个文件;

void WriteFile(WordTable *pwt)
{
	const char *path="D://2.txt";
	assert(pwt!=NULL);
	int len;
	len=pwt->usedsize<1000?pwt->usedsize:1000;//三目运算,如果我们储存的单词,小于1000,就将usedsize给len,否则就等于1000
	FILE *fw=fopen(path,"w");
	assert(fw!=NULL);
	char arr[100]; //用来格式化输出

	for(int i=0;i<len;i++)
	{
		sprintf(arr,"%s出现次数是%d\n",pwt->elem[i].word,pwt->elem[i].count);//对输出的内容进行格式化
		fwrite(arr,sizeof(char),strlen(arr),fw);
	}
	fclose(fw);
}

到此,函数功能已经实现,接下来还有工作!
我们需要释放开辟过的动态空间,大家可以实现后发表留言进行交流。


希望这篇博客可以帮助到你!

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

Borange54

老板大气!

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值