字符串匹配算法有很多,我们先来介绍简单的BF算法,后面还有PK算法,BM算法,KMP算法等,我会一篇一篇和大家一块讨论。
BF算法的原理与实现
我们先来了解两个概念:主串和模式串,简单的说,如果在字符串a中查找字符串b,那么字符串a就是主串,字符串b就是模式串。我们把主串的长度记作n,模式串的长度记作m。在一般情况下,n大于或等于m,虽然这不是必须的,但如果n小于m,那么主串中肯定不存在模式串。
BF(Brute Force,暴力匹配)算法也称暴力匹配算法,从名字可以看出,这种匹配方式很“暴力”,简单直接,性能不高。
作为简单和暴力的字符串匹配算法,BF算法的思想可以用一句话概述:如果模式串长度为m,主串长度为n,那么在主串中就会有n-m+1个长度为m的子串,我们只需要暴力地对比这n-m+1个子串与模式串,就可以找到主串与模式串匹配的子串,当然,在具体处理的过程中,并不是把n-m+1个子串都事先罗列出来,而是通过下标操作,让起始下标分别为0,1,2,...,n-m的子串与模式串尝试匹配。
下面看看一个简单的代码
//返回第一个匹配起始下标的位置
int bf(char[] a,int n,char[] b,int m){
for(int i = 0;i < n-m;i++){
int j = 0;
while(j < m){
if(a[i+j] != b[j]){
break;
}
j++;
}
if(j == m){
return i;
}
}
return -1;
}
BF算法的性能分析
之前我们说过,时间复杂度表示为数据规模n这一个变量的表达式,但是,在有些情况下,时间复杂度会表示为两个变量的表达式,比如说,O(nm),O(n+m)。对于字符串匹配算法,其时间复杂度表示为,需要主串数据规模n和模式串数据规模m共同参与。
从BF算法的原理和代码可以看出来,在极端情况下,如果子串为"aaaa,,,aaaa",模式串为"aaab"。我们用主串中的n-m+1个子串与模式串匹配,每个子串与模式串都需要对比m个字符,这样才能发现无法匹配,因此,最坏时间复杂度为O(nm)。
理论上的BF算法的时间复杂度很高,但是在实际开发中,却是一个比较常用的字符串匹配算法,下面来看看这三条原因。
第一:开发中的大部分情况下的模式串和主串不会很长,对于小规模的数据处理,时间复杂度的高低并不能代表代码真正的执行时间,有些情况下,时间复杂度高的算法可能会比时间复杂度底的算法运行效率更高。
第二:当每次模拟串与主串中的子串匹配时,如果遇到不能匹配的字符,就可以提前终止,不需要把m个字符全部遍历一遍。因此,算法的执行效率要比最坏情况下的效率要高。
第三:BF算法的思想简单,代码实现也简单。
现在来讨论一下为啥在大部分编程语言中,字符串的查找,替换函数都是采用简单的BF算法来实现,而不是采用时间复杂度更低的KMP或者BM算法呢?其实,尽管BF算法的时间复杂度比KMP和BM算法的时间复杂度高,但是相对来说,他们实现起来确是更加的复杂,针对小规模字符串匹配,BF算法才是首选。