字符串匹配BF算法和KMP算法

本文通过具体实验介绍了串模式匹配的基本概念,实现了两种常见的模式匹配算法:BF算法和KMP算法,并提供完整的C语言源代码。此外,还展示了一个简单的算法用于将数组中的正数与负数分离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

16学年—17学年第 1学期 数据结构 实验任务书

专业名称:              实验学时:    2    

课程名称:数据结构      任课教师:  翟海霞     

实验题目: 串的模式匹配算法实现                  

实验环境:    Visual C++ 6.0                   

实验目的

理解串的特点和几种不同的存储结构,掌握基本的运算(赋值、比较、连接,模式匹配……等),比较模式匹配BF算法和KMP算法;  

 

实验内容:

1.实现串的赋值及模式匹配算法。

2.设任意n个整数存放于数组A(1:n)中,试编写算法,将所有正数排在所有负数前面(要求算法复杂性为0(n))。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>   
#define MaxSize 100 //串的最大长度   
//串的定长顺序储存结构   
typedef struct//  
{    
    char ch[MaxSize];//储存串的一维数组  
}sstring;

int  Index_BF(sstring S,sstring T,int pos)
{
	int i=pos,j=0;
	while(i<strlen(S.ch)&&j<strlen(T.ch))//两个串均未到串尾 
	{
		if(S.ch[i-1]==T.ch[j])
		i++,++j;//继续比较后续字符 
		else
		i=i-j+1,j=0;
	}
	if(j==strlen(T.ch)) return i-strlen(T.ch);//匹配成功 
	else return 0;//匹配失败 
}
int main()
{
sstring S,T;
int pos,ans;
printf("输入主串S:\n");
scanf("%s",S.ch);
printf("输入字串T:\n");	
scanf("%s",T.ch);
printf("请输入pos的值:");    
scanf("%d",&pos);        
ans=Index_BF(S,T,pos); 
printf("子串T在主串S中第pos个字符之后的位置为:");   
printf("%d\n",ans);      
system("pause");    
  return 0;  

}

KMP算法

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct
{
	char ch[MAXSIZE+1];
}sstring;
void get_next(sstring T,int next[])
{
	//求模式串T的next函数值并存入数组
	int i=1,j=0; 
	next[1]=0;
	while(i<strlen(T.ch))
	{
		if(j==0||T.ch[i]==T.ch[j]){
			++i;++j;
			next[i]=j;
		}
		else j=next[j];
	}
 } 
int Index_KMP(sstring S,sstring T,int pos,int next[])
{
	//利用模式串T的next函数求T在主串S中第pos个字符后的位置,其中T非空
	int i=pos,j=0;
	while(i<strlen(S.ch)&&j<strlen(T.ch))//两个串均未到末尾
	{
		if(j==0||S.ch[i]==T.ch[j])
		++i,++j;
		else j=next[j];//模式串向后移动 
	 } 
	 if(j>=strlen(T.ch)) return i-strlen(T.ch); //匹配成功 
	 else return 0;//匹配失败
 } 
int main()
{
	sstring S,T;
	int pos,ans,next[MAXSIZE];
	printf("请输入主串S:\n");
	scanf("%s",S.ch);
	printf("请输入模式串T:\n");
	scanf("%s",T.ch);
	printf("请输入pos的值:\n");
	scanf("%d",&pos);
	get_next(T,next);  
    ans=Index_KMP(S,T,pos,next);  
 if(ans==0)  
 printf("匹配失败\n");  
 else  
    printf("模式T在主串S中第pos个字符开始第一次出现的位置为:%d\n",ans);  
	return 0;
 } 
 


计算next函数修正值

void get_nexttval(SString T,int nextval())  
{  
    int i,j;  
    i=1;  
    nextval[1]=0;  
    j=0;  
    while(i<T.length)  
    {  
        if(j==0||T.ch[i]==T.ch[j])  
        {  
            ++i;++j;  
            if(T.ch[i]!=T.ch[j])  
              nextval[i]=j;  
            else nextval[i]=nextval[j];  
        }  
        else  
            j=nextval[j];  
    }  
}  


正数置于负数前

#include<algorithm>
using namespace std;
#include <iostream>
void ni(char *str)
{

	if(*str)
	{
	ni(str+1);
	cout<<*str;
	}
}
int main()
{
	char str[10]="nihao";
	ni(str);
	printf("\n");
	return 0;
}

void Arrange(int A[],int n) 
//n个整数存于数组A中,本算法将数组中所有正数排在所有负数的前面
{int i=0,j=n-1,x;  //用类C编写,数组下标从0开始
 while(i<j)
{while(i<j && A[i]>0)  i++;
while(i<j && A[j]<0)  j--;
   if(i<j) {x=A[i]; A[i++]=A[j]; A[j--]=x; }//交换A[i] 与A[j]
}// while(i<j)
 }//算法Arrange结束.



### BF算法KMP算法的实现方式 #### BF算法 暴力匹配BF算法是一种简单的字符串匹配方法。该算法通过逐一比较主串模式串中的字符来查找匹配项。具体来说,在每次不匹配的情况下,主串指针会回溯到上一次匹配起始位置之后的一个新位置,而模式串则重新从头开始匹配[^2]。 ```java public boolean bf(String text, String pattern) { int n = text.length(); int m = pattern.length(); for (int i = 0; i <= n - m; ++i) { int j; for (j = 0; j < m && pattern.charAt(j) == text.charAt(i + j); ++j); if (j == m) return true; // 找到了完整的匹配 } return false; } ``` #### KMP算法 相比之下,KMP算法利用了部分匹配的信息以避免不必要的重复扫描。当遇到不匹配的情况时,不是简单地将主串指针向前推进一位并重置模式串指针至开头,而是依据预先计算好的`next`数组调整模式串的位置继续尝试匹配。这样可以显著减少比较次数,提高效率[^3]。 ```java public class KMP { private static final void computeLPSArray(char[] pat, int M, int lps[]) { int length = 0; // 长度 of the previous longest prefix suffix int i = 1; lps[0] = 0; // LPS 的第一个值总是 0 while (i < M) { if (pat[i] == pat[length]) { length++; lps[i] = length; i++; } else { if (length != 0) { length = lps[length - 1]; } else { lps[i] = 0; i++; } } } } public static int KMPSearch(String txt, String pat) { int N = txt.length(), M = pat.length(); char T[] = txt.toCharArray(); char P[] = pat.toCharArray(); int lps[] = new int[M]; /* Preprocess the pattern */ computeLPSArray(P, M, lps); int i = 0; // index for txt[] int j = 0; // index for pat[] while ((N - i) >= (M - j)) { if (P[j] == T[i]) { j++; i++; } if (j == M) { System.out.println("Found pattern at index " + (i-j)); j = lps[j-1]; } // mismatch after j matches else if (i < N && P[j] != T[i]) { // Do not match lps[0..lps[j-1]] characters, // they will match anyway if (j != 0) j = lps[j-1]; else i = i+1; } } return -1; } } ``` ### 性能对比 对于最坏情况下的时间复杂度而言: - **BF算法**: O(n * m),其中n为主串长度,m为模式串长度。这是因为每当发生失配时,都需要回到之前的状态重新开始比较。 - **KMP算法**: O(n + m),因为预处理阶段构建`next`数组的时间开销是O(m),而在实际搜索过程中每个字符最多只会被访问两次——一次作为主串的一部分,另一次可能是在模式串内参与比较。因此整体性能更优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值