您的位置:首页 > 理论基础 > 数据结构算法

数据结构之字符串的模式匹配

2015-08-25 21:49 399 查看
字符串的模式匹配问题:

一共有两种算法,

1.朴素模式匹配算法。

举例而言(寻找从S=”goodgoogle”中找到V=”google”这个子串):我们一般需要以下的步骤

(1).从主串的第一个字符开始,S与V中的字符逐一比较,可以发现前三个匹配成功而第四个没有匹配成功(竖线代表成功,折现代表失败)。

         


(2)主串的开始下表+1,又继续与子串进行匹配

        




(3)如果没有匹配成功那么继续重复第二步,直到全部匹配成功,或者直到s到达末尾匹配失败。

        


实现代码:

//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0.
//T非空,1<= pos <=s.length
Public int ndex(String s,String v,int pos){
int i = pos-1; // i用于主串s中当前位置下标,若pos不为0,则从post的位置开始
int j = 0; // j用于子串v的当前位置下标。
while(i<s.length && j<v.length){ //若i小于s的长度,且j小于v的长度时循环
if(s[i] == v[j]){
//如果当前主串对应字符和子串对应字符相等
i++;
J++
}else{
//说明在匹配某个过程中,当前s的对应字符与v对应字符不相等。
i = i - j + 1; //退回到上次匹配开始的下一个字符
j = 0; //将J退回到子串的开头
}
}
if (j > v.length-1){
return i - v.length + 1;
}else {
return 0;
}
}
对于上面的算法,我提出一些改进意见就是,匹配的终止条件可以具体一些,减少循环的次数。当主串的剩余子串长度小于要寻找的子串长度时,就可以停止匹配了。

可以在while中比较两个字符串相等位置的代码之前,加一个大的判断if(s.length-1 - i < v.length ),如果满足条件直接break,跳出循环,后面的字符可以不用比较。

 

 

2.KMP模式匹配算法(是对1算法的改进)。

  假如有主串 S= “abcdefgab”;  匹配子串:T=”abcdex”;我们使用上面的朴素匹配法过程如下。

 


如果我们认真观察其实可以发现②③④⑤步骤是不需要的,是重复的无用操作。因为我们可以发现对于子串的首字符a并不与后面任意一个字符相等,并且如果出现①中的这种现象,子串的前5个字符与主串相等,那么就意味着子串T不可能在于主串S中的2-5号字符相等,2-5号操作是多余的。这就是KMP算法改进朴素算法的地方。

 

KMP模式匹配算法的核心是:如果我们知道子串T的首字符与T中后面的字符均不相等(这是前提),如果在出现如①的情况,即子串的前部分与主串的前部分字符相等,但是从i号不相等,那么我们可以断定以2 到 i-1号任意一个字符开头的字符串不可能与子串匹配成功,那么主串的2 到 i-1号不需要进行判断,直接从i号开始判断。

 


 

 

如果子串中有与首字符重复的子符,该怎么办?我们以S=”abcabcabc” T=”abcabx”为例说明。首先继续朴素匹配算法。

 


因为首字符a有重复,我们不能继续运用上面的规则,但是我们可以发现,到第二个出现首字符之前的字符我们是可以使用规则,将其规避掉,即②与③去掉,不要判断。

因此:对于子串中有与首字符相等的字符,可以省略掉一部分不需要的判断。

这里如何判断与首字符相同的不同位置字符,对算法的影响,参考《大话数据结构》P139.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息