4.3.2
串的模式匹配的改进算法 上页中第二个动画演示的匹配过程正是本节要讨论的模式匹配的改进算法,它是由三位计算机学者 D.E.Knuth 与 V.R.Pratt 和 J.H.Morris 同时发现的,因此人们通常简称它为 KMP 算法。可以证明它的时间复杂度为O(m+n),直观地看,是因为在匹配过程中指针 i 没有回溯。KMP算法的核心思想是利用已经得到的部分匹配信息来进行后面的匹配过程。 回顾上页所举实例,假设主串为 | 从上页同样一个实例的两个匹配过程可见,简单算法之所以时间复杂度会在最坏情况下达到"二次级" 是因为,当进行"两个子串的比较"过程中,不管是 T 串的第几个字符发生"不等"的情况,指针 i 都必须 "回溯" 到S串中原来开始进行比较的字符的下一个位置。而在第二个匹配过程中,当发生两个串中字符比较不等时指针 i 不需要回溯,而只要将 T 串向右滑动到一定位置继续进行字符间的比较。如上例中,S串中除了第3、7和10个字符和T串中的字符比较了两次之外,其它字符和T串中的字符均只进行了一次比较。
| |||||||||||||||||||||||||||||||||||||||||||||||||||
定义:![]() 例如,下列所示为模式串的 next 函数值的两个例子。
|
next 函数值的含义是:当出现 ![]() ![]() ![]() ![]() ![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||
![]() int Index_KMP(char S[], char T[], int pos) { // 利用模式串T的next函数求T在主串S中第pos个字符之后第一次 // 出现的位置的KMP算法。其中1≤pos≤StrLength(S) i = pos-1; j = 0; while ( S[i] != '\0' && T[j] != '\0' ) if (j = = -1 || S[i] = = T[j]) { ++i; ++j; } // 继续比较后继字符 else j = next[j]; // 模式串向右移动 }//while if ( T[j] == '\0' ) return (i-j); // 匹配成功 else return 0; } // Index_KMP | 仔细比较算法4.8和4.7,你一定会发现这两个算法只有两个地方不同,一是当
S[i]![]() 从 next 函数值的定义看,next[0]=-1,因此while 循环中出现j=-1的情况,只能是在 S[i] ![]() |