@songpfei
2016-06-01T23:08:27.000000Z
字数 2174
阅读 1590
数据结构
串(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();
else
return 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.length
m=p.length
π=COMPUTE-PREFIX-FUNCTION(P)
q=0 //number of characters matched
for i=1 to n //scan the text from left to right
while q>0 and P[q+1]≠T[i]
q=π[q] //next characters does not match
if P[q+1]==T[i]
q=q+1 //next character matches
if q==m //is all of P matched ?
print"Pattern occours with shift" i-m
q=π[q] //look for the next match
COMPUTE-PREFIX-FUNCTION(P)
m=P.length
let π[1...m] be a new array
π[1]=0
k=0
for q=2 to m
while k>0 and P[k+1]≠P[q]
k=π[k]
if P[k+1]==P[q]
k=k+1
π[q]=k
return π
/*计算前缀函数数组 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);
}