klice's blog

stay hungry, stay foolish
[数据结构]字符串匹配算法

字符串匹配算法,指在字符串S中,寻找与匹配字符串T相等的子串,如果存在子串,则返回第一个子串的位置,如果不存在子串,则返回-1.

 

普通实现方法

思路:从字符串S的起始位置开始做比较,如果子串和字符串T不相等则向后移动一位,继续比较,直到找到相等的子串,或者已经查找了所有子串。

代码:

View Code
/// <summary>
/// find the index of string T in string S
/// </summary>
/// <param name="S"></param>
/// <param name="T"></param>
/// <returns>if found, return index, else return -1</returns>
public static int GetIndex(string S, string T)
{
int i = 0, j = 0, NotFound = -1, sLen = S.Length, tLen = T.Length;
if (sLen < tLen)
return NotFound;

while (i < sLen && j < tLen)
{
if (S[i] == T[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (j == tLen)
return i - tLen;
else
return NotFound;
}

 

KMP实现方法

思路:从字符串S的起始位置开始做比较,当比较结果为不相等时,假设S的当前位置为i,T的当前位置为j,检查是否存在一个最大值k,满足0<=k<j-1,并且T0Tk与Tj-k-1Tj-1这两个子串相等

如果k不存在,那么同普通实现方法。

如果k存在,此时T0Tk=Tj-k-1Tj-1,而且从之前的比较结果我们可以得知Tj-k-1Tj-1=Si-k-1Si-1,所以可以断定T0Tk=Si-k-1Si-1,所以此时我们不必重新比较T0Tk和Si-k-1Si-1这两个子串,而是比较Si-1和Tk之后的字符是否相等,即i不回退,j回退到k+1,然后继续比较。

现在的问题,转变为如何求这个k,由定义可知,当j=0的时候,k肯定不存在,next[0]=-1,

我们假设next[j]=k,由此可知T0Tk=Tj-k-1Tj-1

如果Tk+1=Tj,那么可推得T0Tk+1=Tj-k-1Tj,即next[j+1]=k+1;

如果Tk+1!=Tj,那么继续比较Tj和Tnext[k+1],如果依然不相等,继续比较Tj和Tnext[next[k+1]],直至Tj与Tn相等,那么next[j+1]=next[n],或者不存在k

代码:

View Code
public static int GetIndexKMP(string S, string T)
{
int i = 0, j = 0, NotFound = -1, sLen = S.Length, tLen = T.Length;
int[] next = GetNextVal(T);
if (sLen < tLen)
return NotFound;
while (i < sLen && j < tLen)
{
if (j == -1 || S[i] == T[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j == tLen)
return i - tLen;
else
return NotFound;
}

/// <summary>
/// get the next value array of a string T
/// </summary>
/// <param name="T"></param>
/// <returns></returns>
public static int[] GetNextVal(string T)
{
int i = 0, j = -1, tLen = T.Length;
int[] next = new int[tLen];
next[0] = -1;

while (i < tLen - 1)
{
if (j == -1 || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
return next;
}



posted on 2011-12-30 23:03  klice  阅读(472)  评论(0)    收藏  举报