@songpfei
2016-06-01T15:08:27.000000Z
字数 2174
阅读 1833
数据结构
串(string):是零个或多个字符串组成的有限序列,又名叫字符串。
子串的定位操作通常称作串的模式匹配。
using namespace std;/**************************函数功能:串的朴素匹配参数说明:S:主串 T:子串pos:开始查找子串的初始位置说明:返回子串T在主串S中第pos个字符之后的位置。若不存在,则返回值为0**************************/int Index(string s, string t, int pos){int i = pos;//主串的起始索引位置int j = 0;//子串的起始索引位置while (i < s.length() && j < t.length()){if (s[i] == t[j]){++i;++j;}else{i = i - j + 2;//返回上次匹配的下一位置j = 0;}}if (j == t.length())return i - t.length();elsereturn 0;}
D.E.Knuth、J.H.Morris和V.R.Pratt(其中,Knuth和Partt共同研究,Morris独立研究)发表一个模式匹配算法,可以大大避免重复遍历的情况,称之为克努特--莫里斯--普拉特算法,简称KMP算法。
参照:http://kb.cnblogs.com/page/176818/
"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。
"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,
- "A"的前缀和后缀都为空集,共有元素的长度为0;
- "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
- "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
- "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
- "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
- "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
- "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。
KMP-MATCHER(T,P)//T:主串 P:子串(模式字符)n=T.lengthm=p.lengthπ=COMPUTE-PREFIX-FUNCTION(P)q=0 //number of characters matchedfor i=1 to n //scan the text from left to rightwhile q>0 and P[q+1]≠T[i]q=π[q] //next characters does not matchif P[q+1]==T[i]q=q+1 //next character matchesif q==m //is all of P matched ?print"Pattern occours with shift" i-mq=π[q] //look for the next match
COMPUTE-PREFIX-FUNCTION(P)m=P.lengthlet π[1...m] be a new arrayπ[1]=0k=0for q=2 to mwhile k>0 and P[k+1]≠P[q]k=π[k]if P[k+1]==P[q]k=k+1π[q]=kreturn π
/*计算前缀函数数组 pattern*/int* ComputePreFix(const string &P){int m = P.length();int *pattern = new int[m];pattern[0] = 0;int k = 0;for (int q = 1; q < m; q++){while (k>0 && P[k] != P[q])k = pattern[k - 1];if (P[k] == P[q])k += 1;pattern[q] = k;}return pattern;}/* KMP法进行字符串匹配*/void KMP_matcher(const string &T, const string &P){int n = T.length();int m = P.length();int* pattern = ComputePreFix(P);int q = 0;//已匹配的字符串个数for (int i = 0; i < n; i++){while (q>0&&P[q]!=T[i])q = pattern[q - 1];if (P[q] == T[i])q += 1;if (q == m){cout << "Pattern occours with shift " << i - m+1;q = pattern[q - 1];}}delete pattern;pattern = NULL;}
int main(){string T = "goodababacgooleababaca";string P = "ababaca";KMP_matcher(T, P);}