【数据结构】串模式匹配算法

  1. 实现功能: 从主串中第K个字符起,求出子串在主串中首次出现的位置,即模式匹配或串匹配。要求用三种模式匹配算法分别实现:
    1. 朴素的模式匹配算法(BF算法)
    2. KMP改进算法(Next[ ])
    3. KMP改进算法(NextVal[ ])
  2. 设计要求:

首先设计一个含有多个菜单项的主控菜单程序,然后再为这些菜单项配上相应的功能。

程序运行后,给出5个菜单项的内容和输入提示:

1.输入主串、子串和匹配起始位置

2.朴素的模式匹配算法

3.KMP改进算法(Next[ ])

4.KMP改进算法(NextVal[ ])

0.退出管理系统

请选择0—4:

菜单设计要求:使用数字0—4来选择菜单项,其它输入则不起作用。

输出结果要求:输出各趟匹配详细过程(其中3、4,首先输出Next[ ]或者NextVal[ ]的各元素的数值),然后输出匹配总趟数、单个字符比较次数、匹配成功时的位置序号或者匹配失败提示信息。

 

#include<stdio.h>
#include<string.h>

#define maxn 100000

/*
bacbababadababacamba
ababaca

aaabaaaab
aaaab
*/

/*
  菜单二:输出各趟匹配的详细过程、匹配总趟数、单个字符比较次数、匹配成功时的位置序号或匹配失败提示信息
  菜单三:输出next[]各元素数值、各趟匹配详细过程、匹配总趟数、单个字符比较次数、匹配成时的位置序号或匹配失败提示信息
  菜单四:输出nextval[]各元素数值、各趟匹配详细过程、匹配总趟数、单个字符比较次数、匹配成时的位置序号或匹配失败提示信息 
*/ 

char s[100],t[100],ss[maxn],tt[maxn]; 	//主串与模式串,ss与pp为了检验子串与主串的长度 
int next[maxn],nextval[maxn],chcom[maxn];	//chcom数组记录字符比较次数 

void print(); 
void Input();
void init();	//初始化各个数组 
void BF();
void KMP(int y);
void get_next();
void get_nextval();
int jiancei();

int main(){
	
	while(1){
		char i[100];
		print();
		scanf("%s",&i[0]);
		
		if(strlen(i)!=1||i[0]<'0'||i[0]>'4'){		//检验输入
            printf("输入错误,请输入0-4中的数字\n");
            continue;
        }
        
        if(i[0]=='1'){
            Input();
        }
        else if(i[0]=='2'&&strlen(s)!=0&&strlen(t)!=0){
            BF();
        }
        else if(i[0]=='3'&&strlen(s)!=0&&strlen(t)!=0){
            get_next();
            KMP(0);
        }
        else if(i[0]=='4'&&strlen(s)!=0&&strlen(t)!=0){
            get_nextval();
            KMP(1);
        }
        else if(i[0]=='0'){
            printf("系统退出,感谢使用\n");
            break;
        }
        else if(strlen(s)==0||strlen(t)==0){
            printf("请先输入主串和模式串之后再进行匹配!\n");
        }
        else{
            printf("输入错误,请输入0-4中的数字\n");
            continue;
        }
	}	
	return 0;
}

void print(){
	printf("**************************************************\n");
    printf("*        1.输入主串、子串                        *\n");
	printf("*        2.朴素的模式匹配算法                    *\n");
	printf("*        3.KMP算法(Next[])                       *\n");
	printf("*        4.KMP改进算法(NextVal[])                *\n");
	printf("*        0.退出管理系统                          *\n");
	printf("--------------------------------------------------\n");     	
	printf("         请输入你要选择的功能:\n");
} 

void Input(){
	printf("请输入主串:");
	getchar();
    scanf("%[^\n]",ss);		// \n作为字符串输入的结束符,不能用%s,否则会把“ ”当作结束符 
    if(strlen(ss)>100){
        printf("主串长度应不大于100,请重新输入!\n");
        Input();
    }
    printf("请输入子串:");
    scanf("%s",tt);
    if(strlen(tt)>100){
        printf("模式串长度应不大于100,请重新输入!\n");
        Input();
    }
    int i;
    for(i=0;ss[i]!='\0';i++){
		s[i]=ss[i];
    	printf("%c",s[i]); 
	}  
    s[i]='\0';
    printf("\n");
    for(i=0;tt[i]!='\0';i++){
    	t[i]=tt[i];
    	printf("%c",t[i]);
	}
    t[i]='\0';
	printf("\n"); 
    int m=strlen(s);
    int n=strlen(t);
    if(m<n){
        printf("主串长度应不小于模式串长度!请重新输入!\n");
        Input();
    }
}

void init(){	//初始化 
	for(int i=0;i<maxn;i++){
        chcom[i]=0;
        next[i]=0;
        nextval[i]=0;
    }
}

int jiancei(){
	int n,ret=0;
	int m=strlen(s);
	do{
		ret=scanf("%d",&n);
		if(ret!=1){
			printf("输入有误,请重新输入1-%d之间的数字\n",m);
			fflush(stdin);
		}
		else if(n>m||n<1){
			printf("输入有误,请重新输入1-%d之间的数字\n",m);
			fflush(stdin);	
		}
	}while(ret!=1||n>m||n<1);
	//cout<<"输入的值为"<<n<<endl;
	return n;
}

void BF(){
	printf("----------------------------------------------------------------------------------------------\n");
	init();	//初始化 
	int pos;	
	printf("请输入匹配的起始位置\n");
	pos=jiancei();
	int i=pos,j=1;
	int m=strlen(s);
    int n=strlen(t);
    printf("----------------------------------------------------------------------------------------------\n");
	while(i<=m && j<=n){
		chcom[i-1]++;
		if(s[i-1]==t[j-1]){
			printf("主串第 %d 项与模式串第 %d 项匹配成功\n",i,j);
			i++;
			j++;
		}
		else {
			printf("主串第 %d 项与模式串第 %d 项匹配失败,从主串第 %d 项、模式串第%d项开始匹配\n",i,j,i-j+2,1);
			i=i-j+2;
			j=1;	
		}
	}
	printf("----------------------------------------------------------------------------------------------\n");
	if(j>n){
		printf("字符串匹配成功,匹配总趟数为%d,位置序号为%d\n",i-n,i-n);
		printf("----------------------------------------------------------------------------------------------\n");
		for(int x=0;x<m;x++){
			printf("第%d项比较次数为%d\n",x+1,chcom[x]);
		}
	}
	else{
		printf("匹配失败\n"); 
	}
	printf("----------------------------------------------------------------------------------------------\n");
}

void get_next(){
    init();
    int i=1;
    next[1]=0;
    int j=0;
    int n=strlen(t);
    while(i<n){
    	if(j==0 || t[i-1]==t[j-1]){
    		i++;
    		j++;
    		next[i]=j;
		}
		else{
			j=next[j];
		}
	}
	printf("----------------------------------------------------------------------------------------------\n");
	for(int x=0;x<n;x++){
		printf("next[ %d ]= %d \n",x+1,next[x+1]);
	}
}

void get_nextval(){
	init();
    int i=1;
    nextval[1]=0;
    int j=0;
    int n=strlen(t);
    while(i<n){
    	if(j==0 || t[i-1]==t[j-1]){
    		i++;
    		j++;
    		if(t[i-1]!=t[j-1]){
    			nextval[i]=j;
    		}
			else{
    			nextval[i]=nextval[j];
			}
		}
		else{
			j=nextval[j];
		}
	}
	printf("----------------------------------------------------------------------------------------------\n");
	for(int x=0;x<n;x++){
		printf("nextval[ %d ]= %d \n",x+1,nextval[x+1]);
	}
}

void KMP(int y){
	printf("----------------------------------------------------------------------------------------------\n");
	init();	//初始化 
	int pos;	
	printf("请输入匹配的起始位置\n");
	pos=jiancei();
	int i=pos,j=1;
	int m=strlen(s);
    int n=strlen(t);
    int r=0;	//总匹配趟数 
    printf("----------------------------------------------------------------------------------------------\n");
    while(i<=m && j<=n){
    	chcom[i-1]++;
    	if(j==0 || s[i-1]==t[j-1]){
    		if(j!=0){
    			printf("主串第 %d 项与模式串第 %d 项匹配成功\n",i,j);
			}
    		i++;
    		j++;
		}
		else{
			r++; 
			if(y==0){
				if(next[j]==0){
					printf("主串第 %d 项与模式串第 %d 项匹配失败,从主串第 %d 项、模式串第1项开始匹配\n",i,j,i+1);	
				}
				else{
					printf("主串第 %d 项与模式串第 %d 项匹配失败,从主串第 %d 项、模式串第%d项开始匹配\n",i,j,i,next[j]);
				}
				j=next[j];
			}
			if(y==1){
				if(nextval[j]==0){
					printf("主串第 %d 项与模式串第 %d 项匹配失败,从主串第 %d 项、模式串第1项开始匹配\n",i,j,i+1);	
				}
				else{
					printf("主串第 %d 项与模式串第 %d 项匹配失败,从主串第 %d 项、模式串第%d项开始匹配\n",i,j,i,nextval[j]);
				}
				j=nextval[j];
			}
		} 
	}
	printf("----------------------------------------------------------------------------------------------\n");
	if(j>n){
		printf("字符串匹配成功,匹配总趟数为%d,位置序号为%d\n",r+1,i-n); 
		printf("----------------------------------------------------------------------------------------------\n");
		for(int x=0;x<m;x++){
			printf("第%d项比较次数为%d\n",x+1,chcom[x]);
		}
	}
	else{
		printf("匹配失败\n");
	}
	printf("----------------------------------------------------------------------------------------------\n");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值