문자열 매칭 ----- BF 알고리즘과 KMP 알고리즘

임기 말에 데이터 구조를 검토하기 위해 내 자신의 통찰력과 이해의 일부를 적어 두었습니다. 우선, 내 자신의 요구 사항에서 나는 내 코드에서 간결하고 명확하게 노력하고 어려운 곳에 주석을 달 것입니다.

기사 디렉토리


문자열 매칭: BF 매칭 과정 및 구현, KMP에서 패턴 문자열의 다음 값 계산 및 매칭 과정, 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
}

2. KMP 알고리즘

코드는 다음과 같습니다
. unsigned, 즉 음수가 아닌 숫자, 이 유형은 int보다 하나 더 많은 이진수를 저장할 수 있습니다. 즉, 모든 이진 비트는 정보를 저장하는 데 사용되며 데이터가 양수인지 여부를 판단하는 부호 비트가 없습니다. 부정적인)

다음 배열의 흥미로운 값은 패턴 문자열과만 관련이 있습니다.

//得到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的修正值
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