BM算法---c语言

学习好几天的BM算法,今天他来了!

为了方便操作我创建了两个文件 省的一直输入 浪费时间!
(但代码要是复制黏贴过去 需要自己穿件两个文本 在计算机的c盘的文档里 zhuchuan zichuan)

思路

好后缀和坏字符法一起用;分别放入不同的函数中 将x i j指针传入函数,返回位移量;好后缀还需要用到另外新建一个指针j

这里用到坏字符规则
在这里插入图片描述

在这里插入图片描述
这里写的是好后缀的过程 当然程序写的时候还得都比较一下
在这里插入图片描述
好后缀中,y和j比较 再和j-1比较都不相同,若有相同的则把y向后移动一位 再与j-1比较、
在这里插入图片描述
在这里插入图片描述
这里a位移到c下边是因为怕有漏的;一样的,如果有三个字符的好后缀则移动到第二个好后缀下;
在这里插入图片描述
此处坏字符规则;
在这里插入图片描述
此处好后缀
在这里插入图片描述
此时匹配完成;
速度非常快;

测试:

这里我为了更好看见代码的错误,是分开用坏字符和好后缀的 最后再给两个加个比较看哪个位移量跟多 就选哪一种方式;

若你自己写的好后缀或坏字符代码,可以测试这几个

坏字符:

1.

主abcdabca
子abca

2.

主abcbabca
子abca

3.

主abcbacab
子acab

4.

主abcbabab
子abab

好后缀

1.

abcdababacab
abacab

2.

abcdabbacdab
bacdab

3.

abcdababcdba
abcdba

4.

abcdabbacdaa
bacdaa

最后再来一个 综合的
abcdabbacdababcdba
abcdba

当然,一个好的代码一定得经得住上万字符搜索的操作;可以随机输入几百个字符然后复制黏贴,让代码跑起来;看还能搜做到不;
例如:
在这里插入图片描述
子串是:abcdbaabcdbaabcdba
运行结果:在这里插入图片描述
没有出错就很舒服:
得劲儿!!!!!!!!!!!!!!
不多bibi 上代码:

代码介绍:

文件操作就不介绍了 之前写过好多次了;
这里是坏字符原则代码:

int huai(int i,int j,int x)//坏字符 
{
	int y=0;
	while(str[j]==stri[x])//选取坏字符时后面可能有相同的字符此时需要跳过;
	{
		j--;
		x--;
		if(j<0)//此时是判断是否匹配成功;
			return -1;
	}
	 
	while(str[j]!=stri[x])//这里是检测坏字符;直到找到相同的时跳出,y就是位移量;
	{
		
		if(str[j]!=stri[x])
		{
			j--;
			y++;
		}
		
		if(j<=0)//这里是怕匹配的都不相同,这时位移量挺大的;
			return y;
	}
	
			if(x>=zhushu-1)//当时调试代码是老是溢出 我就设置了一下终点;
			{
				printf("没找到\n"); 
				return -2;
			}
			
	return y;
 } 

好后缀原则代码:

int hao(int i,int j,int x)//好后缀 
{
	
	int y=0;
	int m,n,z;
	while(str[j]!=stri[x])//把好后缀后边的不相同的跳过;
	{
		if(j<0)//处理当字符都不相同时的情况;
			return 1;
		j--;
		x--;
		if(x>zhushu-1)//此时也是防止溢出 zhushu是主字符数组字符的总长
			 return -2; 
		}	
	i=x;//若主串前半部分不相等  则m和i x不相等 
	z=0;
	
	 while(str[j]==stri[x])//遇到相同的字符把x 和j向前移动; 方便后边匹配;
	 {
	 		
	 	x--;
	 	j--;
	 	z++;
		//
		if(z==zong)//当z与子串总长相同时 匹配成功!
			return -1;
	 	if(j<0)//同上  可忽略;
	 		return 1;	
	 }
	 
	 while(1)//此时x已指向相同后边的字符 之后遇到相同字符相同时需要移动i  若i和x未相等字符不匹配了 这是i利用m回归原位再进行匹配;
	 {
	 	m=i;
	 	
	 	while(str[j]==stri[i])
		 {
		 	i--;
		 	j--;
	 		y++;
	 		if(j<0)
	 			break;
	 		if(i==x)
			 	break; 
		 }
		
		 if(j<0)
	 		break;
		 while(str[j]!=stri[i])
		 {
		 	i=m;
		 	j--;
		 	y++;
		 	if(j<0)
		 		break;
		 	if(i==x)
			 	break;	
		 }
		 
		if(j<0)
		 	break;
		if(i==x)//到这里说明符合了好后缀原则 找到了 与好后缀相同的字符 返回位移量
			break;		
	 }			
	
	if(y==zong)
		return -1;
	return y;
}

这个是选择好后缀还是坏字符代码:

void chazhao()
{
	printf("主串长度%d 子串长度%d\n",zhushu,zong);
	int x=zong-1,i=zong-1,j=zong-1;//从0开始计算zong-1,   最后结尾时也是zhushu-1与他相等;
	int huaifan=0,haofan=0;
	while(1)  
	{
		
			huaifan=huai(i,j,x);//函数
			
			haofan=hao(i,j,x);
			
			if(huaifan>=haofan)
			{
				x=x+huaifan;
				i=x;
				j=zong-1;
			}
			else
			{
				x=x+haofan;
				i=x;
				j=zong-1;
			}
			
			if(huaifan==-1||haofan==-1)
			{
				x++;
				printf("\n子串在主串%d的位置\n",x);
				break;
			}	
			if(huaifan==-2)
				break;	
			if(haofan==-2)
			{
				printf("没找到!\n");
				break;
				}	
	 } 
	 
	return;
}

完整代码:

//BM算法; 
#include<stdio.h> 
#include<stdlib.h>

char str[50];//子串 
char stri[10000000];//主串长度 修改处 
int zhushu;//主串总字符 
int zong; //子串总字符 
void shuru();
void shuchu();
void chazhao();

int huai(int i,int j,int x);
int hao(int i,int j,int x);

int  main()
{
	 
	shuru();
	chazhao();
	shuchu();
	
}
//===============================================================
void shuru()
{
	FILE *fp,*fq;
	int h,e;
	if((fp = fopen("zichuan.txt","r")) == NULL)//输入子串字符 
	{
		printf("can not open this file \n");
		exit(0);
	}
	h=ftell(fp);
	fseek(fp,0,2);
	e=ftell(fp);
	fseek(fp,0,0);
	
	zong=e;
	
	while(e-h>0)//文件中的字符导入到子字符数组 
	{
		//printf("%d %d ",h,e);
		fscanf(fp,"%c",&str[h]);//一个回车 三个字符去存它   会使字符数组增加三个 
		h++;
	}
		
	fclose(fp);
	
	if((fq = fopen("zhuchuan.txt","r")) == NULL)//输入主串字符 
	{
		printf("can not open this file \n");
		exit(0);
	}
	
	h=ftell(fq);
	fseek(fq,0,2);
	e=ftell(fq);
	fseek(fq,0,0);
	//printf(" h=%d\n ",h);
	zhushu=e-h;
	while(e-h>0)//文件中的字符导入到主字符数组; 
	{
		
		fscanf(fq,"%c",&stri[h]);
	//	printf("%c ",stri[h]);
		h++;
	}
		
	fclose(fq);
}
//========================================================
void shuchu()
{
	int i=0;
	while(i<zong)
	{
		printf("%c",str[i]);
		i++;
	}
	i=0;
	printf("\n");
	
	while(i<zhushu)
	{
		printf("%c",stri[i]);
		i++;
	}
	
}
//==========================================
void chazhao()
{
	printf("主串长度%d 子串长度%d\n",zhushu,zong);
	int x=zong-1,i=zong-1,j=zong-1;//从0开始计算zong-1,   最后结尾时也是zhushu-1与他相等;
	int huaifan=0,haofan=0;
	while(1)  
	{
		
			huaifan=huai(i,j,x);
			
			haofan=hao(i,j,x);
			
			if(huaifan>=haofan)
			{
				x=x+huaifan;
				i=x;
				j=zong-1;
			}
			else
			{
				x=x+haofan;
				i=x;
				j=zong-1;
			}
			
			if(huaifan==-1||haofan==-1)
			{
				x++;
				printf("\n子串在主串%d的位置\n",x);
				
				
				break;
			}	
			if(huaifan==-2)
				break;	
			if(haofan==-2)
			{
				printf("没找到!\n");
				break;
				}	
	 } 
	 
	return;
}
//===========================================================
int huai(int i,int j,int x)//坏字符 
{

	int y=0;
	while(str[j]==stri[x])
	{
		j--;
		x--;
		
		if(j<0)
			return -1;
		
	}
	 
	while(str[j]!=stri[x])
	{
		
		if(str[j]!=stri[x])
		{
			j--;
			y++;
		}
		
		if(j<=0)
			return y;
	}
	
			if(x>=zhushu-1)
			{
				printf("没找到\n"); 
				return -2;
			}
			
	return y;
 } 
//+===============================================
int hao(int i,int j,int x)//好后缀 
{
	
	int y=0;
	int m,n,z;
	while(str[j]!=stri[x])
	{
		if(j<0)
			return 1;
		j--;
		x--;
		
		
		if(x>zhushu-1)
			 return -2; 
		}	
	
	i=x;//若主串前半部分不相等  则m和i x不相等 
	z=0;
	
	 while(str[j]==stri[x])
	 {
	 		
	 	x--;
	 	j--;
	 	z++;
		if(z==zong)
			return -1;
	 	if(j<0)
	 	{
	 		
	 		return 1;
		 }
	 		
	 		
	 }
	 
	 while(1)
	 {
	 	m=i;
	 	
	 	while(str[j]==stri[i])
		 {
		 	i--;
		 	j--;
	 		y++;
	 		
	 		if(j<0)
	 			break;
	 		if(i==x)
			 	break; 
			 	
		 }
		 
		 if(j<0)
	 		break;
		 while(str[j]!=stri[i])
		 {
		 	i=m;
		 	j--;
		 	y++;
		 	if(j<0)
		 		break;
		 	if(i==x)
			 	break;	
		 }
		 
		if(j<0)
		 	break;
		if(i==x)
			break;		
	 }			
	
	
	if(y==zong)
		return -1;
	
	
	return y;
}

//abcdabbbacdababcdba
//             abcdba

//aaaaab
//aaaab









  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值