字符串的模式匹配

来源:互联网 发布:德国狂屠巴西 知乎 编辑:程序博客网 时间:2024/05/16 16:08

字符串的模式匹配是数据结构中很重要的一部分内容,它是字符串的一个应用。记得当时吴暇老师给我们将数据结构的时候多次强调的,已经还给老师多年,今天来review下。

所谓模式匹配是这个意思:有两个字符串,such as  “abbcabd"   n   ”bca”。求bca是不是abbcabd的子串,如果是就返回在abbcabd中出现的bca的下标值。在这个demo中是2。那么abbcabd叫作目标串(subject),bca叫模式串(pattern)

模式匹配一个直观的算法就是逐个进行匹配检验。也就是从目标串的第0个元素开始和模式串的第0个元素进行比较。如果相等,再从模式串的第1个元素和目标串的第1个元素进行比较。。。如果一旦不相等,就回退回去。这里有一个BF算法。实现如下:

int BFMatch(std::string subject, std::string pattern) {        if(subject.size()<pattern.size()) return -1;         int i=0,j=0;        while(i<subject.size() && j<pattern.size()){                if(subject.at(i)==pattern.at(j)){                        i++;                        j++;                }else{//元素不相等的时候                        i=i-j+1;//指针回溯到进行匹配的位置                        j=0;//模式串从回到第0位置再进行下一次的匹配                }           }           if(j>=pattern.size()) return i-pattern.size();        return -1;    }
BF的时间复杂度最好的情况下是O(m),最坏的情况下是O(n*m),其中m是模式串的长度,n是目标串的长度。


对BF算法进行优化,就有了大名鼎鼎的KMP算法。KMP利用了模式串本身的对称性,在进行匹配失败的时候,i指针不用进行回溯。而是根据 j的在next数组中的值进行处理。

如果next[j]==-1:i和j都指向下一个字符;

如果next[j]==k(k!=-1):j不用从0开始,而是从模式串上的第k个位置开始,在进行匹配

所以在BF算法的基础上只要进行一点点的改动就有了KMP下的模式匹配,实现如下:

int KMPMatch(std::string subject, std::string pattern) {        if(subject.size()<pattern.size()) return -1;        next(std::string pattern, next);//next数组通过这个方法已经得到        int i=0,j=0;        while(i<subject.size() && j<pattern.size()){                if(subject.at(i)==pattern.at(j)){                        i++;                        j++;                }else{//元素不相等的时候                                                j=next[j];//模式串从回到第next[j]位置再进行下一次的匹配                }           }           if(j>=pattern.size()) return i-pattern.size();        return -1;    }
so,剩下的问题就是怎么计算next数组。next数组的计算可以说是KMP算法最最精彩的部分,当时学的时候也是很confuse,后来终于是理解了。next数组有多重计算方法,得出的值也是不尽相同,现在展示两种教程上的。分别记为next和nextVal,后者是前者的改进。代码如下:
void getNextArray(char pattern[], int next[]) {        if (pattern==NULL) return;        int j=0,k=-1;        next[0] = -1;        while(pattern[j]!='\0'){                if(k==-1 || pattern[j]==pattern[k]){                        next[++j] = ++k;                }else{                        k = next[k];                }        }        return;}
void getNextArrayAdvanced(char pattern[], int next[]) {        if (pattern==NULL) return;        int j=0,k=-1;        next[0] = -1;        while(pattern[j]!='\0'){                if(k==-1 || pattern[j]==pattern[k]){                        if(pattern[++j]!=pattern[++k]){                                next[j] = k;                        }else{                                next[j]=next[k];                        }                }else{                        k = next[k];                }        }        return;}
anyway,详细的内容可以参考我们的教科书:李春葆的《数据结构教程》第二版,以及这两个blog,我觉得写的很清晰推荐下:

http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

http://www.cnblogs.com/yjiyjige/p/3263858.html

0 0