数据结构——KMP算法

来源:互联网 发布:淘宝店托管 编辑:程序博客网 时间:2024/04/29 12:03

1.什么是模式匹配

自己看看百度百科,模式匹配、简单模式匹配

https://baike.baidu.com/item/%E6%A8%A1%E5%BC%8F%E5%8C%B9%E9%85%8D/1258334?fr=aladdin

2.模式匹配的KMP算法的优点

        KMP算法是对简单模式匹配算法的改进,简单模式匹配算法,每次模式串(子串)匹配不同时,模式串都要从头开始匹配,理论上时间复杂度为O(m*n),效率不高,KMP算法当某一个字符匹配不同时是从特定的位置开始的,该位置前所有字符都一一与主串不匹配位置的字符匹配,时间复杂度为O(m+n),大大提高效率。

        最大优点是匹配时,主串索引不需要回溯,这样当数据量大时,可以分段操作,先读入内存一部分进行匹配,完成之后可写回外存,确保在发生不匹配时不需要将之前写回外存的部分再次读入,减少了I/O操作

注:为了方便理解,串的字符数组都是从下标为1开始存储字符,字符数组第一个元素存放串的长度

如果应用中是从下标0开始存储字符,则相应next数组值相差1

3.KMP算法

KMP算法由两部分实现第一步是实现模式串的getNext()函数,得到next数组

next[j]表示模式串第j个字符不匹配时,应从next[j[处的字符重新与主串比较

/** * @author 芜情 * KMP算法,这里直接从0开始,没按照书上的从索引1开始存储 */public class MyString {private char[] s;//赋值public MyString(char[] chs){if(chs == null){s = null;return;}if(s != null){s = null;//释放原串空间}s = new char[chs.length+1];s[0] = (char) chs.length;for(int i = 1; i < s.length; i++){s[i] = chs[i-1];}}//模式匹配public int indexOf(MyString T){char[] t = T.s;int[] next = getNext(t);int i = 1, j = 1;while(i <= s[0] && j <= t[0]){if(j == 0 || s[i] == t[j]){++i;++j;}else{j = next[j];}}if(j > t[0]){return i - t[0];}return -1;//匹配不成功}//next()函数//next[j]表示在第j个字符不匹配时,模式串重新匹配的位置//next[j] = k,说明对模式串T有T[1] = T[j-k+1],...,T[k-1] = T[j-1](共k个)public int[] getNext(char[] chs){int[] next = new int[chs.length];next[1] = 0;//第1个字符不匹配,则模式串右移,模式串第1个字符跟主串下一个字符比较//分析时是倒着推,写程序得正着来,因为要求next[i+1]得先知道next[i]的值int i = 1, j=next[i];while(i < chs[0]){//j=0代表递归到next[1]了,此时表达式形式上同p(j)=p(i)时的情况if(j == 0 || chs[i] == chs[j]){//此种情况next[i+1] = next[next[i]] + 1//即 next[i+1] = j + 1++i;++j;next[i] = j;//p(j)=p(i)时的表达式next[i+1]=next[i]+1}else{j = next[j];//继续递归}}return next;}}
4.KMP算法的改进——nextVal()函数

//改进的next()函数nextVal()//有事重新定位匹配位置时,刚好第一个就不匹配,又得调用一次next()函数//nextVal()函数就是一次搞定,保证调用一次nextVal()起码匹配位置往后移一个public int[] getNextVal(char[] chs){int[] nextVal = new int[chs.length];nextVal[1] = 0;int i = 1, j=nextVal[i];while(i < chs[0]){if(j == 0 || chs[i] == chs[j]){++i;++j;if(chs[i] != chs[j]){nextVal[i] = j;}else{nextVal[i] = nextVal[j];}}else{j = nextVal[j];}}return nextVal;}


不管是next数组还是nextVal数组,索引都是从1开始,它代表是串的第几个元素,而数组的值则是根据实际情况,看设定的是从0开始还是从1开始
原创粉丝点击