串的匹配-----BF算法和KMP算法

出于对期末的数据结构复习,我写下我自己的一些见解和认识。首先出于对我自己的要求,我对自己的代码力求简洁明了,并且会在难懂的地方注释。

文章目录


串匹配:BF匹配过程及实现、KMP中模式串next值的计算及匹配过程、改进的KMP中模式串nextval


提示:以下是本篇文章正文内容,下面案例可供参考(c++)

一BF算法

最好情况下的时间复杂度为O(n+m),n为主串长度,m为子串长度
最坏情况下的时间复杂度为O(n*m)。

代码如下(示例):

//暴力匹配算法
//需要传入主串,匹配位置,模式串(要匹配的串)
bool BF(string S,int pos,string T) {
    
    
	//直接对主串的pos位置到pos+模式串的长度考试匹配,只要有一处不等就直接返回false
	for (int i = 0; i < T.length();i++) {
    
    
		if (T[i]!=S[pos+i]) {
    
    
			return false;//匹配失败
		}
	}
	return true;//匹配成功
}

接下来是经典的使用场景
使用这个算法主要就是可以得到模式串在主串的全部位置,所以需要一个循环来对主串全操作

int main() {
    
    
	string s = "12341234567651日2任然";
	string s1 = "12";
	//输出主串中模式串所在的位置,
	//主串最后不足模式串的长度的部分没有意思,因为一定不会存在想要的答案
	//说实话,为了使用一个函数而写一个循环,我觉得这样有违写函数的目的,函数就是为了将操作变成一行
	for (int i = 0; i < s.length()-s1.length();i++) {
    
    
		if (BF(s,i,s1)) {
    
    
			cout << i<<" ";
		}
	}
	//结果0 4
	return 0;
}

BF经典算法
虽然较长,但是在使用的时候非常方便,只需要传入主串,模式串,初始匹配位置,就可以返回第一个模式串的位置。

//这个算法只能返回一个位置
int BF(string S,string T,int pos) {
    
    
	int i = pos, j = 0;
	while (i < S.length()&&j<T.length()) {
    
    //两串均为比较到串尾
		if (S[i]==T[j]) {
    
    
			i++; j++;
		}else {
    
    
			i = i - j + 1;//位置后移
			pos = i;//更新pos的位置
			j = 0;
		}
	}
	if (j == T.length()) return pos;
	else return -1;//没有找到返回-1
}

二.KMP算法

代码如下(示例):
我在一下代码中使用的unsigned(无符号位)都可以用int代替,我之所以这样是为了减少警告(小知识:串的长度的类型就是unsigned,即非负数,这个类型可以比int存储多一位二进制的数,即全部的二进制位都用来存储信息,没有符号位用来判断数据的正负)

有意思的next数组的数值仅与模式串有关。

//得到next数组
void get_next(int next[],string T) {
    
    
	next[1] = 0; next[2] = 1;
	unsigned i = 2, j = 1;//这里的i和j都代表数学位置,所以在下面的对串的所以的使用要-1
	while (i <= T.length()) {
    
    
		//如果两个位置的字符相等就让i后面一个位置等于j+1
		if (j==0||T[i-1]==T[j-1]) {
    
    
			i++, j++;
			next[i] = j;//i和j都已自加
		}else {
    
    
			j = next[j];
		}
	}
}

//这个返回的是数学位置,不是索引,可以在返回的最后的-1即可
int KMP(string S,string T) {
    
    
	unsigned i = 1, j = 1;
	static int next[10];
	get_next(next,T);
	while (i<=S.length()&&j<=T.length()) {
    
    
		if (j==0||S[i-1]==T[j-1]){
    
    
			i++, j++;
		}
		else {
    
    
			j = next[j];
		}
	}
	if (j>T.length())return i - T.length()//返回数学位置
	else return -1;
}

int main() {
    
    
	string s = "1233414322";
	string s1 = "233";
	cout << KMP(s,s1);
	return 0;
}
//结果为2

改进的next求解方法,减少模式串和主串的无用匹配

//改进的next求解方法
//计算next的修正值
void get_nextval(string T, int nextval[]) {
    
    
	int i = 1, j = 0;
	while (i < T.length()) {
    
    
		if (j == 0 || T[i] == T[j]) {
    
    
			i++, j++;
			if (T[i] != T[j]) nextval[i] = j;
			else nextval[i] = nextval[j];
		}else j = nextval[j];
	}
}

结束语:我自己能够在复习后理解,翻阅文章主要便于记忆

猜你喜欢

转载自blog.csdn.net/blastospore/article/details/122050330