平时我们使用的字符串查找,都是用语言自带的字符串查找函数,比如php中使用strpos(string,find,start);C#中使用string.indexof(),C++中的strstr()等函数,但是这些函数的效率却并不高。如果要在长度为n的字符串A中,查找长度为m的字符串B,它们最坏的时间复杂度为O(m*n),随着子字符串长度m的增大,这些函数的时间复杂度也相应地成倍增加。
现在我们介绍一下一些常用的字符串查找算法:
1、我们先写出来最一般最常用的查找字符串的算法:
function indexOf($parent,$find,$start) { $_start=$start; $parent_len=strlen($parent); $find_len=strlen($find); $temp=0; for(;$_start<=$parent_len-$find_len;$_start++){ $tmp=$_start; $find_num=0; while($find_num<$find_len){ if($parent[$tmp]==$find[$find_num]){ $tmp++; $find_num++; } else{ break; } } if($find_num>=$find_len){ echo "find successfully<br/>the position is ".($_start+1); break; } } }
2、KMP(Knuth-Morris-Pratt ): 之所以叫做KMP,是因为这个算法是由Knuth、Morris、Pratt三个提出来的
排序原理:
1、我们将字符串A和B比较,在A中查找B字符串,来证明B字符串是否是A的子串。
2、上面我们写出了普通的求B是A的字串的算法,你会发现,当B中的j位置的字符和A中i位置的字符不想等的时候,就将我们的j重置为零,在这里就非常浪费了我们查找字符串的效率,而kmp节约的效率主要是在这里。
3、在kmp算法中,他不会因为两个字符不相等而直接将j重置为0,而是设置了一个next数组来确定当两个字符不相等的时候,将j附什么样的值。
4、这个next数组就是在两个字符串中的字符不相等的时候,尽量让B字符串向后移动的长度。
可以参考http://www.matrix67.com/blog/archives/115/
http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html
function getNext($strFind)
{
$next[0]=-1;
$j=0;
$k=-1;
while($j<strlen($strFind)-1)
{
if($k==-1||$strFind[$j]==$strFind[$k]) //匹配的情况下,p[j]==p[k]
{
$j++;
$k++;
$next[$j]=$k;
}
else //p[j]!=p[k]
$k=$next[$k];
}
return $next;
}
function indexOf($parent,$find,$start,$next) { $_start=$start; $parent_len=strlen($parent); $find_len=strlen($find); $temp=0; while($_start<=($parent_len-$find_len)||$temp<$find_len){ if($parent[$_start]==$find[$temp]){ $_start++; $temp++; } else{ $temp=$next[$temp]; } if($temp==-1){ $temp=0; $_start++; } } if($temp>=$find_len){ echo "find successfully! the position is ".($_start-$find_len+1); } else{ echo "failure"; } }
3、BM算法