C语言实现数据结构之文章编辑(KMP算法)

任务

静态存储一页文章,每行最多不超过80个字符,共N行。统计文中所出现的英文字母的个数、数字的个数、空格的个数、总字数等。

分析

使用结构体存储文章,结构体成员包含每一行的字符串结点以及指向下一行结点的指针,采用链式存储。对于统计字符串使用KMP算法。

存储结构设计
typedef struct text { //
	char sline[90];
	struct text *next;
} TEXT;
源代码
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
#define N 100

typedef int bool;
#define true 1
#define false 0

int nextval[N];//存储nextval的值
int place[N];
int OverlayValue[N];
int num[4]= {0}; //num[0]代表空格 num[1]代表字母 num[2]代表数字 num[3]代表单词个数

typedef struct text { //
	char sline[90];
	struct text *next;
} TEXT;

bool isAlphabet(char t);//如果字符是字母就返回真
bool isDigit(char t);//如果是数字就返回真
bool isSpace(char t);//是空格就返回真
int wordnum(char *t);//统计某一行的单词数量
void GetNextval(char const *ptr,int plen,int *nextval); //求nextval
int kmp1(char const *scr,int slen,char const *ptr,int plen,int const *nextval,int pos);//求字符串中模式串的个数
int search(char const *scr,char const *ptr);///在主串中找到字串的位置,没有返回零
bool delet(char *scr,char const *ptr);//删除指定的字串。
bool readtext(TEXT *head,int n);//读入文章
void release(TEXT *head);//释放节点
void OutputText(TEXT *head);//在屏幕上输出文字
int countword(TEXT *head,char const *ptr);//统计文章中某个单词的个数
void countother(TEXT *head);//统计文章中的空格,字母,数字和单词的个数
int deltext(TEXT *head,char const *ptr,int *OverlayValue);//删除文章中的指定单词
void OverlayFun(char const *ptr,int *OverlayValue);//覆盖函数

int main() {
	TEXT *head;
	head=(TEXT *)malloc(sizeof(TEXT));
	if(head==NULL) {
		printf("内存分配失败
");
		return -1;
	}
	printf("请输入你要写入的文章的行数: ");
	int n;
	scanf("%d",&n);
	getchar();
	readtext(head,n);
	
	int code;
	printf("--------------------文章编辑系统----------------------
");
	printf(" | 1.统计文章英文字母数、空格数及总字数                |
");
	printf("------------------------------------------------------
");
	printf(" | 2.统计某一字符串在文章中出现的次数                  |
");
	printf("------------------------------------------------------
");
	printf(" | 3.删除某一字符串                                    |
");
	printf("------------------------------------------------------
");
	printf(" | 0.退出系统                                          |
");
	printf("------------------------------------------------------
");
	while(1) {
		printf("
请选择操作:"); 
		scanf("%d", &code);
		switch(code) {
			case 1: countother(head);
					printf("文章中英文字母数:%d
空格数:%d
总字数:%d
",num[1],num[0],num[0]+num[1]+num[2]);
					break;  
			case 2: printf("请输入你要查找的字符串: ");
					char t[80];
					scanf("%s",t);
					GetNextval(t,strlen(t),nextval);
					int thewordnum=countword(head,t);
					printf("你查找的字符串在文章中的个数是:%d
",thewordnum);
					break;  
			case 3: printf("请输入你要删除的单词:");
					char thedel[80];
					scanf("%s",thedel);
					deltext(head,thedel,OverlayValue);
					printf("输出删除后的文章
");
					OutputText(head);
					break;
			case 0: printf("谢谢使用!
");
					release(head);
				    return 0;  
			default: printf("暂不支持该功能!
");
				     break;
		}
		fflush(stdin);			//清空键盘缓冲区
	}

	
}
bool isAlphabet(char t) { //如果字符是字母就返回真
	if(t>='a'&&t<='z' || t>='A'&&t<='Z')
		return true;
	else return false;
}
bool isDigit(char t) { //如果是数字就返回真
	if(t>='0' && t<='9')
		return true;
	else return false;
}
bool isSpace(char t) { //是空格就返回真
	if(t==' ')
		return true;
	else return false;
}
int wordnum(char *t) { //统计字符串中的单词个数
	int i;
	bool tag=false;
	bool is=false;
	int wordnum=0;
	for(i=0; i<strlen(t); i++) {
		if(t[i]==' ' && !tag)//忽略字符串开头的空格字符
			continue;
		else tag=true;

		if(t[i]>='a' && t[i]<='z' || t[i]>='A' && t[i]<='Z') {
			is=true;
		} else if((t[i]==' ' || t[i]==',' || t[i]=='.' || t[i]=='
'|| t[i]=='' || t[i]=='?' || t[i]=='!')  && is) { //is为true代表在遇到空格或其他分隔符之前遇到字母
			wordnum++;
			is=false;
		}
	}
	if(is)wordnum++;
	return wordnum;
}

void GetNextval(char const *ptr,int plen,int *nextval) { //求nextval
	int i=0;
	nextval[0]=-1;
	int j=-1;
	while(i<plen-1) {
		if(j==-1 || ptr[j]==ptr[i]) {
			j++;
			i++;
			if(ptr[i]==ptr[j])
				nextval[i]=j;
			else
				nextval[i]=nextval[j];
		} else
			j=nextval[j];
	}
}
// scr 为指向主串的指针,ptr为指向模式串的指针
int kmp1(char const *scr,int slen,char const *ptr,int plen,int const *nextval,int pos) {
	int count=0;//统计字符串中模式串的个数
	int i=pos;
	int j=0;
//	while(i<slen && j<plen)
	while(i<slen) {
		if(j==-1 || scr[i]==ptr[j]) {
			i++;
			j++;
			if(j==plen) {
				count++;
				j=0;
			}
		} else  j=nextval[j];
	}
//	if(j>=plen)
//		return i-plen;
//	else return -1;
	return count;
}

void OverlayFun(char const *ptr,int *OverlayValue) {
	int plen=strlen(ptr);
	OverlayValue[0]=-1;
	int i,index=0;
	for(i=1; i<plen; i++) {
		index=OverlayValue[i-1];
		while(index>=0 && OverlayValue[i]!=OverlayValue[index+1]) {
			index=OverlayValue[index];
		}
		if(OverlayValue[i]==OverlayValue[index+1])
			OverlayValue[i]=index+1;
		else OverlayValue[i]=-1;
	}
}
int search(char const *scr,char const *ptr) {
	int slen=strlen(scr);
	int plen=strlen(ptr);
	memset(place,-1,sizeof(place));
	int pindex=0,sindex=0;
	int t=0;
	while(sindex<slen) {
		if(scr[sindex]==ptr[pindex]) {
			sindex++;
			pindex++;
			if(pindex==plen) {

				place[t++]=sindex-pindex;
				//pindex=0;
			}
		} else if(pindex==0)
			sindex++;
		else pindex=OverlayValue[pindex-1]+1;
	}
	return t;
}
bool delet(char *scr,char const *ptr) {
	int len=search(scr,ptr);
	int plen=strlen(ptr);
	int slen=strlen(scr);
	int sum=0;
	char temp[80];
	if(len==0) { //在主串中没有找到模式串
		return false;
	}
	int j=0,r=0;
	for(int i=0; i<slen; i++) {
		if(i==place[j]) {
			j++;
			i=i+plen-1;
			continue;
		}
		temp[r++]=scr[i];
	}
	temp[r]='';
	strcpy(scr,temp);
	return true;
}
int  deltext(TEXT *head,char const *ptr,int *OverlayValue) {
	OverlayFun(ptr,OverlayValue);
	TEXT *p=head->next;
	int tag=0;
	while(p) {
		if(!delet(p->sline, ptr)) {
			//	printf("无法删除");
			//	exit(0);
			tag++;
		}
		p=p->next;
	}
	return tag;
}
bool readtext(TEXT *head,int n) {

	if(n<=0) return false;
	TEXT *p=head;

	printf("请输入你的文章,每行不超过80个字符
");
	while(n--) {
		char temp[80];
		gets(temp);
		TEXT *s=(TEXT *)malloc(sizeof(TEXT));
		if(s==NULL)return false;
		strcpy(s->sline,temp);
		s->next=NULL;
		p->next=s;
		p=s;
	}
	return true;
}
void release(TEXT *head) {
	TEXT *p=head,*q;
	while(p) {
		q=p->next;
		free(p);
		p=q;
	}
}

void OutputText(TEXT *head) {
	TEXT *p=head->next;
	while(p) {
		printf("%s
",p->sline);
		p=p->next;
	}
}

int countword(TEXT *head,char const *ptr) {
	int count=0;
	TEXT *p=head->next;
	while(p) {
		count+=kmp1(p->sline,strlen(p->sline),ptr,strlen(ptr),nextval,0);
		p=p->next;
	}
	return count;
}

void countother(TEXT *head) {
	TEXT *p=head->next;
	int i;
	while(p) {
		for(i=0; i<strlen(p->sline); i++) {
			if(isAlphabet(p->sline[i]))
				num[1]++;
			if(isSpace(p->sline[i]))
				num[0]++;
			if(isDigit(p->sline[i]))
				num[2]++;
		}
		num[3]+=wordnum(p->sline);
		p=p->next;
	}
}
运行结果