字符串匹配

标签(空格分隔): 数据结构


1 串的定义

串(string):是零个或多个字符串组成的有限序列,又名叫字符串。

2. 朴素模式匹配算法

子串的定位操作通常称作串的模式匹配

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;

}

3. KMP模式匹配算法

D.E.Knuth、J.H.Morris和V.R.Pratt(其中,Knuth和Partt共同研究,Morris独立研究)发表一个模式匹配算法,可以大大避免重复遍历的情况,称之为克努特–莫里斯–普拉特算法,简称KMP算法

3.1 关于前缀及后缀

参照: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。
  

3.2《算法导论》第32章中KMP算法的伪代码:

  1. 计算匹配的位置
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
  1. 计算前缀函数
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 π

3.C语言KMP算法实现

/*计算前缀函数数组 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值