前言
本博客最终会完成以下的任务
使用顺序存储的循环队列实现下面功能:
将文档中每个单词的最后三个字母保存到一个新文档中,并打印在
屏幕上。例如,原文档中有这样一句话“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);
}
}