C语言:顺序存储循环队列#保存文件中单词的最后三个字母

前言

本博客最终会完成以下的任务

使用顺序存储的循环队列实现下面功能:
将文档中每个单词的最后三个字母保存到一个新文档中,并打印在
屏幕上。例如,原文档中有这样一句话“Near the ancient water town
of Wuzhen”,保存完则为“ear the ent ter own of hen”。

全局变量和结构体代码

/*单词顺序表*/
typedef struct _Elem{
	char *word;//存放单词 
	int lenth; 
	int front;
	int rear;
}Elem; 
typedef struct _Elemlink{
	Elem *array;//动态定义数组 
	int link_len;//数组长度  
}Elemlink;
Elemlink *L1 = NULL;
#define MAXSIZE 3//一保存个单词后面的几个字母的最大数量 

四个任务

①计算文件中的单词数量

该操作是为了分配空间,事先一次性分配完所需要的空间。
计算完成后该函数会返回一个int数值,该数值就是单词数量,所以利用这个返回值进行空间分配。

count_to_words函数中的这个isalpha()函数是在ctype.h头文件中的,所以在使用的时候要记得包含该头文件。
isalpha()函数是判断该字符是否为字母

代码思想: 这比较简单,其实就是遇到字母就开始录入,当遇到不是字母形式的或者遇到空间就代表该单词结束录入,数组移动下一个空间,然后等待再次遇到字母形式的字符就开始重复上述操作。

fp1 = fopen("D:/D/F.txt", "r");

F_link_len = count_to_words(fp1);//统计单词表 接收单词数量

L1->array = (Elem*)malloc(sizeof(Elem)*F_link_len+1);
/*分配顺序单词表空间 
,+1 是防止空间越界,
所以多给一个空间位置进行存储
,不会造成什么影响*/
fclose(fp1);
//计算文件中单词数函数
int count_to_words(FILE *fp) //统计删除后的单词个数 
{
	char ch;
	int nums = 0;
	while(!feof(fp))
	{
		ch = getc(fp);
		if(isalpha(ch))
		{
			nums++;
			while(1)
			{
				ch = getc(fp);
				if(!isalpha(ch)) break; 
				/*当完成录入一个单词后进入到这里
				是为了找到下一个字母形式开头的内容才退出循环。*/
			}
		}
	}
	return nums;
}

②保存单词最后三个字母到链表中

使用顺序存储的循环队列实现
如果不理解循环队列的话可以移步到我另一篇博客进行学习喔!里面讲的很详细,一定要耐心看完,都是本尊的心血和全部的学习总结出来的。
->顺序存储的循环队列——点击博客<-

代码里面也有很多注释,你也可以选择去尝试着看注释理解一下我想要表达的意思

void SqQueue_Save_Three_ch(Elemlink **Sqlink, FILE *fp) //先进先出,f出,r进 
{
	char ch;
	int index = 0;
	bool open = false;
	int i;
	Elemlink *temp = (*Sqlink);
	
	Elemlink *malloc_Sq = (*Sqlink);
	for(i = 0; i < F_link_len; i++)
	{//分配每个单词的空间,用最大长度的单词空间分配就能存下所有的
		malloc_Sq->array[i].word = (char*)malloc(sizeof(char)*MAXSIZE);
		malloc_Sq->array[i].rear = 0;
		malloc_Sq->array[i].front = 0;
		malloc_Sq->array[i].lenth = 0;
	}
	
	 
	while(!feof(fp))
	{
		ch = fgetc(fp);
		if(ch != ' ' && isalpha(ch))
		{ 
			open = true;
			//第二个判断条件也很重要,因为第一个进来的时候,肯定是rear = front的,所以要用lenth判断是否已经录入了一个 
			if((temp->array[index].rear)%MAXSIZE == (temp->array[index].front)%MAXSIZE && temp->array[index].lenth!=0) 
			temp->array[index].front = (temp->array[index].front+1)%MAXSIZE;
			/*顺序真的很重要,我靠,上下两部分调开顺序,结果完全不一样,
			必须要先判断是否移动尾指针才进行录入,
			否则的话,
			
			1、假设还没满队 
			若你是先录入,再移动指针的话,你不能保证移动后,
			尾部指针到最后录完之后,会把尾部指针置空了一个
			
			2、假设已经满队了,且录入完成,没有元素进入 
			可能会导致头部指针往后移动了一个,但是没有尾部没有录入,
			这时候会导致头部变成了第二个元素,而尾部变成了第一个元素*/ 
			temp->array[index].word[temp->array[index].rear] = ch;
			temp->array[index].rear = (temp->array[index].rear + 1)%MAXSIZE;
			
			/*过程是:先判断是否加一后和头部指针相同了,
			如果相同了,首先把头部指针往前移动,
			然后再把尾部指针回到刚刚头部指针腾出来的位置,这样就实现了队列排序*/ 
			 
			if(temp->array[index].lenth < MAXSIZE)
			{
				temp->array[index].lenth++;
			} 
			
		}
		if(open == true && ch == ' ') 
		{
			open = false;
			index++;
		}
		
	}
	
 } 

③将链表的内容导出到另一个文件中

长话短说,这里录入尽量用fprintf,虽然本博客讲的是英文单词,我希望以后你想向文件输入中文信息的时候不会出现乱码的错误,所以我推荐大家使用fprintf来操作,同样的你想读取文件中某些中文信息的时候也要使用fscanf,这都是文本文件操作所使用的函数。
想要了解为什么或者会实战了解一下可以移步我另一篇博客喔。
为什么删除超链接要是用fprintf…点击博客

导出内容的函数代码如下:

void SaveFile_Sq_Three_ch(Elemlink *Sqlink, FILE *fp)
{
	int i, j, count = 0;
	for(i = 0; i < F_link_len; i++)
	{
		
		for(j = 0; j < Sqlink->array[i].lenth; j++)//Sqlink->array[i].lenth
		{
			fprintf(fp,"%c", Sqlink->array[i].word[Sqlink->array[i].front]);
			Sqlink->array[i].front = (Sqlink->array[i].front+1)%MAXSIZE;
		}
		fprintf(fp,"\t");
		count++;
		if(count%10==0)
		{
			count = 0;
			fprintf(fp,"\n");
		}
	}
}

④将新文件的内容打印到屏幕中

这个就很简单啦,第三步中说到,我们在读取中文信息的时候一定要用fscanf,这里我们用的是单词作为例子,不包含中文符号,所以这里博主就偷个懒哈哈哈, 直接用fgetc函数。
代码如下:

void PF_Three_ch_File(FILE *fp)
{
	char ch;
	int i = 0;
	while(!feof(fp))
	{
		ch = fgetc(fp);
		if(ch != ' ' && ch != '\n')
		{
			putchar(ch);
			break;
		}
	}
	while(!feof(fp))
	{
		ch = fgetc(fp);
		putchar(ch);
	}
}

@完整代码@

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
/*单词顺序表*/
typedef struct _Elem{
	char *word;//存放单词 
	int lenth; 
	int front;
	int rear;
}Elem; 
typedef struct _Elemlink{
	Elem *array;//动态定义数组 
	int link_len;//数组长度  
}Elemlink;
Elemlink *L1 = NULL;
#define MAXSIZE 3//一保存个单词后面的几个字母的最大数量 
int F_link_len; 

int count_to_words(FILE *fp);
void SqQueue_Save_Three_ch(Elemlink **Sqlink, FILE *fp); 
void SaveFile_Sq_Three_ch(Elemlink *Sqlink, FILE *fp);
void PF_Three_ch_File(FILE *fp);


int main()
{
	FILE *fp1;
	L1 = (Elemlink*)malloc(sizeof(Elemlink));//建立一个顺序表的空间 ,地址是全局变量,出了函数后也不会被释放 
	
	fp1 = fopen("D:/D/F.txt", "r");
	F_link_len = count_to_words(fp1);//统计单词表 接收单词数量
	L1->array = (Elem*)malloc(sizeof(Elem)*F_link_len+1);//分配顺序单词表空间 
	fclose(fp1);
	

	fp1 = fopen("D:/D/F.txt", "r");
	SqQueue_Save_Three_ch(&L1, fp1);
	fclose(fp1);
	
	fp1 = fopen("D:/D/F_Threech.txt", "w");
	SaveFile_Sq_Three_ch(L1, fp1);
	fclose(fp1);
	
	
	fp1 = fopen("D:/D/F_Threech.txt", "r");
	PF_Three_ch_File(fp1);
	fclose(fp1);

	return 0; 
}

int count_to_words(FILE *fp) //统计删除后的单词个数 
{
	char ch;
	int nums = 0;
	while(!feof(fp))
	{
		ch = getc(fp);
		if(isalpha(ch))
		{
			nums++;
			while(1)
			{
				ch = getc(fp);
				if(!isalpha(ch)) break; 
				/*当完成录入一个单词后进入到这里
				是为了找到下一个字母形式开头的内容才退出循环。*/
			}
		}
	}
	return nums;
}

void SqQueue_Save_Three_ch(Elemlink **Sqlink, FILE *fp) //先进先出,f出,r进 
{
	char ch;
	int index = 0;
	bool open = false;
	int i;
	Elemlink *temp = (*Sqlink);
	
	Elemlink *malloc_Sq = (*Sqlink);
	for(i = 0; i < F_link_len; i++)
	{//分配每个单词的空间,用最大长度的单词空间分配就能存下所有的
		malloc_Sq->array[i].word = (char*)malloc(sizeof(char)*MAXSIZE);
		malloc_Sq->array[i].rear = 0;
		malloc_Sq->array[i].front = 0;
		malloc_Sq->array[i].lenth = 0;
	}
	
	 
	while(!feof(fp))
	{
		ch = fgetc(fp);
		if(ch != ' ' && isalpha(ch))
		{ 
			open = true;
			//第二个判断条件也很重要,因为第一个进来的时候,肯定是rear = front的,所以要用lenth判断是否已经录入了一个 
			if((temp->array[index].rear)%MAXSIZE == (temp->array[index].front)%MAXSIZE && temp->array[index].lenth!=0) 
			temp->array[index].front = (temp->array[index].front+1)%MAXSIZE;
			/*顺序真的很重要,我靠,上下两部分调开顺序,结果完全不一样,
			必须要先判断是否移动尾指针才进行录入,
			否则的话,
			
			1、假设还没满队 
			若你是先录入,再移动指针的话,你不能保证移动后,
			尾部指针到最后录完之后,会把尾部指针置空了一个
			
			2、假设已经满队了,且录入完成,没有元素进入 
			可能会导致头部指针往后移动了一个,但是没有尾部没有录入,
			这时候会导致头部变成了第二个元素,而尾部变成了第一个元素*/ 
			temp->array[index].word[temp->array[index].rear] = ch;
			temp->array[index].rear = (temp->array[index].rear + 1)%MAXSIZE;
			
			/*过程是:先判断是否加一后和头部指针相同了,
			如果相同了,首先把头部指针往前移动,
			然后再把尾部指针回到刚刚头部指针腾出来的位置,这样就实现了队列排序*/ 
			 
			if(temp->array[index].lenth < MAXSIZE)
			{
				temp->array[index].lenth++;
			} 
			
		}
		if(open == true && ch == ' ') 
		{
			open = false;
			index++;
		}
		
	}
	
 }

void SaveFile_Sq_Three_ch(Elemlink *Sqlink, FILE *fp)
{
	int i, j, count = 0;
	for(i = 0; i < F_link_len; i++)
	{
		
		for(j = 0; j < Sqlink->array[i].lenth; j++)//Sqlink->array[i].lenth
		{
			fprintf(fp,"%c", Sqlink->array[i].word[Sqlink->array[i].front]);
			Sqlink->array[i].front = (Sqlink->array[i].front+1)%MAXSIZE;
		}
		fprintf(fp,"\t");
		count++;
		if(count%10==0)
		{
			count = 0;
			fprintf(fp,"\n");
		}
	}
}

void PF_Three_ch_File(FILE *fp)
{

	char ch;
	int i = 0;
	while(!feof(fp))
	{
		ch = fgetc(fp);
		if(ch != ' ' && ch != '\n')
		{
			putchar(ch);
			break;
		}
	}
	while(!feof(fp))
	{
		ch = fgetc(fp);
		putchar(ch);
	}
}

posted @ 2022-06-19 16:05  竹等寒  阅读(11)  评论(0编辑  收藏  举报  来源