用c语言,串,BF算法实现查询功能

该程序使用BF算法进行串匹配,并实现了匹配结果的可视化显示,用户可自定义每行显示的字符数。程序首先初始化串,然后进行串赋值、清空等操作。BF算法匹配过程中,根据设定的行数动态调整输出,展示模式串在主串中的位置。匹配成功会显示详细信息,失败则提示模式串不存在于主串中。
摘要由CSDN通过智能技术生成
  • 优点:可以自定义显示行数,使交互界面更加美观

  • 缺点:随着设定行数减小,出错的可能性增大(建议30以上),是不完美版本

#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#include<conio.h>

#define OK 1
#define ERROR -1
#define OVERFLOW -2
#define MAX 1000

typedef int Status;

//-----串的堆式顺序存储结构-----
typedef struct{
	char *ch;
	int length;
}HString;

//初始化
Status InitString(HString &s){
	s.ch=NULL;
	s.length;
	return OK;
}

//判空
Status StrEmpty(HString &T){
	if(T.length==0&&T.ch==NULL) return OK;
	else return ERROR;
}

//串赋值
Status StrAssign(HString &T,char *str){
	int i,j;
	InitString(T);
	i=strlen(str);
	if(!i) return ERROR;
	else{
		T.ch=(char*)malloc(i*sizeof(char));
		if(!T.ch)
			exit(OVERFLOW);
		for(j=0;j<i;j++){
			T.ch[j]=str[j];
			T.length=i;
		}
	}
}
	
//清空串
Status ClearStr(HString &s){
	if(s.ch){
		free(s.ch);
		s.ch=NULL;
	}
	s.length=0;
	return OK;
}

//打印串
void StrPrint(HString &s){
	int i;
	if(StrEmpty(s)==OK)
		printf("%d为空串!",&s);
	for(i=0;i<s.length;i++){
		printf("%c",s.ch[i]);
		printf(" ");
	}
}

//BF算法实现串匹配
Status BF(HString S,HString T,int pos){
	int j=0,i;
	i=pos-1;
	while(i<S.length&&j<T.length){
		if(S.ch[i]==T.ch[j]){
			i++;
			j++;
		}
		else{
			i=i-j+1;
			j=0;
		}
	}
	if(j>=T.length){
		return i-T.length;		//此处如果模式串在1位,则i-T.length=0,返回值易冲突,所以ERROR定义不能为0,应为负数
	}							//(i-T.length+1)=temp+1表示模式串在主串中的起始位置
	else
		return ERROR;
}

//显示串匹配成功的信息的功能函数
Status SucceedDisplay(HString S,HString T,int temp,int pos,int Lnum){
	int count=0,count1=0,count2=0,e=0,numone=0,numtwo=0,num3=0,x=0,i=0,j=0,r=0,m=0,n=0,o=0,loc=0,p=0,q=0,u=0,v=0,w=0,y=0,flag=0,num=0;
	printf("匹配成功!\n");
	
	count=S.length/Lnum;
	e=temp;			//第一次产生的空块数
	loc=temp+1;		//记录模式串出现的起始位置
	
	//主串主体输出
	while(count>0){		
		if(count==S.length/Lnum) printf("主串:*********\n");
		if(count==S.length/Lnum) printf("模式串:*******\n");
		count--;				//计数器
		numone++;
		for(i=(numone-1)*Lnum;i<numone*Lnum;i++){	
			printf("%c",S.ch[i]);					//-----------------------输出主串
			printf(" ");
		}
		printf("\n");
		
		if(n==333){
			pos=x+1+T.length;	//当前模式串起始位+T.length=pos(下一次开始匹配位置)
			temp=BF(S,T,pos);	//上一次的temp=BF(S,T,pos)执行了,所以补一次更新temp值再进入下一轮模式串生成循环
			e=temp-x-T.length;		//新的temp-上一次的temp-T.length=“新产生的空块数”
		}

		if(n==666){
			w=e-u;		//w表示“待输出剩余空块数”
	
			//空块数规避
					 
			while(w>=Lnum){	//待输出空块数w在新一行又超过了Lnum,
				num3++;		//计数器,记录输出剩余空块数输出行数
				printf("\n");
				if(count>0&&w>=Lnum){
					w=w-Lnum*num3;
					count--;				//计数器
					numone++;
					for(i=(numone-1)*Lnum;i<numone*Lnum;i++){	
						printf("%c",S.ch[i]);					//-----------------------输出主串
						printf(" ");
					}
					printf("\n");
				}
			}

			if(w<Lnum){	//输出不足Lnum的“输出空块数”或“剩余待输出空块数”
				for(i=0;i<w;i++){	
					printf("  ");	//在当轮主串下方,生成上一轮处在换行处的空块数的后半部分
				}
			}
			v=w+T.length;		//换行处的空块数的后部分(小于Lnum时的w)+T.length,v值还会反过来影响下一轮模式串生成循环
			
			//模式串规避
			if(v<Lnum){
				for(i=0;i<T.length;i++){
					printf("%c",T.ch[i]);
					printf(" ");
				}
				temp=BF(S,T,pos);	//上一次的temp=BF(S,T,pos)执行了,所以补一次更新temp值再进入下一轮模式串生成循环
				e=temp-x-T.length;		//新的temp-上一次的temp-T.length=“新产生的空块数”
			}

			else{		//“剩余待输出空块数+T.length”>Lnum
				for(i=0;i<w;i++){
					printf("  ");
				}
				y=T.length-(T.length-Lnum+w);	//待输出模式串前部分
				for(i=0;i<y;i++){
					printf("%c",T.ch[i]);
					printf(" ");
				}

				if(count>0){
					count--;				//计数器
					numone++;
					for(i=(numone-1)*Lnum;i<numone*Lnum;i++){	
						printf("%c",S.ch[i]);					//输出主串
						printf(" ");
					}
					printf("\n");
				}
				
				if(count>0){
					for(i=0;i<T.length-(Lnum-w);i++){	//待输出模式串后部分
						printf("  ");
					}
					temp=BF(S,T,pos);	//上一次的temp=BF(S,T,pos)执行了,所以补一次更新temp值再进入下一轮模式串生成循环
					e=temp-x-T.length;		//新的temp-上一次的temp-T.length=“新产生的空块数”
				}
			}//else if(v>=Lnum)
		}//if(n==666)

		if(n==999){
			o=T.length-m;			//o为上一轮模式串后部分长度,o值还会反过来影响下一轮模式串生成循环
			for(i=0;i<o;i++){
				printf("%c",T.ch[i]);	//在当轮主串下方,生成上一轮处在换行处的模式串的后半部分
				printf(" ");
			}
			temp=BF(S,T,pos);	//上一次的temp=BF(S,T,pos)执行了,所以补一次更新temp值再进入下一轮模式串生成循环
			e=temp-x-T.length;		//新的temp-上一次的temp-T.length=“新产生的空块数”
		}

	//模式串主体输出
		if(temp!=ERROR){
			n=0;	//重置n的值,供下一次使用
			if(e>=Lnum){
				while(e>=Lnum){		//e>Lnum,情况一
					printf("\n");
					count--;				//计数器
					numone++;
					for(i=(numone-1)*Lnum;i<numone*Lnum;i++){	
						printf("%c",S.ch[i]);					//-----------------------输出主串
						printf(" ");
					}
					printf("\n");
					e=e-50;
					if(e<Lnum){
						for(i=0;i<e;i++){
							printf("  ");
						}
					}
				}
			}
			else{					
				while(temp!=ERROR){
					
					//模式串单行输出
					if(e+T.length<Lnum){				//预测输出后长度并判断,在此之前空格和模式串没有输出过
						count1=e+T.length+v+o;				//特别记录进入这里的空块数和模式串长度的和
						v=0;o=0;		//重置v,o的值,下一次使用
						while(count1<Lnum&&flag==0&&temp!=ERROR){//e<Lnum且前轮(e+T.length)+下轮空块数与模式串长度(e+T.length)<Lnum,情况二
							x=temp;			//暂存旧的temp的值,下一次使用
							for(i=0;i<e;i++){
								printf("  ");		//产生空块
							}
							StrPrint(T);
							numtwo++;			//记录循环次数
							pos=temp+1+T.length;	//当前模式串起始位+T.length=pos(下一次开始匹配位置)	
							//产生新的temp
							temp=BF(S,T,pos);		
							e=temp-x-T.length;		//新的temp-上一次的temp-T.length=“新产生的空块数”
							count2=count1+e;		//累计'前轮'输出后当行的(空块数和模式串长度)的总和+下一轮的空块数
							count1=count1+e+T.length;//累计'下一轮'输出后当行的(空块数和模式串长度)的总和
							if(count2>=Lnum||count1>=Lnum&&temp!=ERROR){
								if(count1=Lnum) num=3;
								if(count2>Lnum) num=2;
								else num=1;
								flag=1;
							}
						}
						flag=0;	//重置flag,保证下次循环
					}
					switch(num){
					case 3:
						if(temp!=ERROR){		//累计'前轮'输出后当行的(空块数和模式串长度)的总和=Lnum,情况五
							for(i=0;i<e;i++){
								printf("  ");
							}
							for(i=0;i<T.length;i++){
								printf("%c",T.ch[i]);
							}
							pos=temp+1+T.length;	//当前模式串起始位+T.length=pos(下一次开始匹配位置)
							numtwo++;			//记录循环次数
							printf("\n");
							n=333;
						}
						break;
					case 2:
						if(temp!=ERROR){//e<Lnum且前轮(e+T.length)+下轮空块数e>Lnum,情况三
							u=Lnum-(count2-e);	//"当前行应输出的空块数"=Lnum-上一轮的(空块数和模式串长度)的总和
							for(i=0;i<u;i++){
								printf("  ");
							}
							pos=temp+1+T.length;	//当前模式串起始位+T.length=pos(下一次开始匹配位置)
							numtwo++;			//记录循环次数
							printf("\n");
							n=666;	//媒介开关,启动在下一模式串行输出当轮剩余空块的后部分
						}
						break;
					case 1:
						if(temp!=ERROR){//e<Lnum且前轮(e+T.length)+下轮空块数与模式串长度(e+T.length)>Lnum,情况四
							for(i=0;i<e;i++){				
								printf("  ");		//产生空块
							}
							m=Lnum-count2;
							if(m==0) printf("\n");
							else{
								for(i=0;i<m;i++){
									printf("%c",T.ch[i]);	//输出处在换行处模式串的前部分
								}
								printf("\n");
							}
							pos=temp+1+T.length;	//当前模式串起始位+T.length=pos(下一次开始匹配位置)
							numtwo++;			//记录循环次数
							n=999;	//媒介开关,启动在下一模式串行输出模式串的后部分
						}
						break;
					}
					x=temp;			//暂存旧的temp的值,下一次使用
					temp=ERROR;			//跳出模式串生成循环去主串生成循环

				}//while(temp!=ERROR)
			}//else
		}//if(temp!=ERROR)
	}//while(count>0)
	printf("\n模式串在主串中的起始位置:第%d位",loc);	//temp+1表示位置,loc=temp+1
	printf("\n模式串在主串中的出现次数:共%d次",numtwo);
	if(temp==ERROR){
		printf("\n匹配结束!\n");
		return 0;
	}
}

//显示串匹配失败的信息的功能函数
Status fail(){
	printf("匹配失败!\n");
	printf("模式串在主串中不存在!\n");
	return 0;
}

void main(){
	HString S,T;
	int temp,pos,Lnum;
	int flag=1,choice=1,q=0,i=0;
	InitString(S);InitString(T);

	printf("\n*******************本程序通过串的BF算法模式匹配,实现查询功能********************\n\n");
	printf("请输入存入主串的字符串:");
	char str1[MAX];gets(str1);
	StrAssign(S,str1);
	printf("请输入存入模式串的字符串:");
	char str2[MAX];gets(str2);
	StrAssign(T,str2);
	while(choice){
		printf("请输入起始匹配的位置(第一位为1):");
		scanf("%d",&pos);
		if(pos==0||pos>S.length)
			printf("输入不合法!");
		else
			choice=0;
	}
	printf("请输入每行显示字数:");
	scanf("%d",&Lnum);
	while(flag){
		printf("\n匹配结果:");
		temp=BF(S,T,pos);
		if(temp==ERROR){
			flag=fail();	
		}
		else{
			flag=SucceedDisplay(S,T,temp,pos,Lnum);
		}
		getch();
		printf("\n程序已退出!\n");
	}
	ClearStr(S);
	ClearStr(T);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钢铁の洪流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值