简介
在主字符串中text
查找子字符串 pattern
是否存在,按照暴力匹配其时间复杂度为O(m*n)。
KMP算法改进了查找效率,核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的,按照KMP算法匹配其时间复杂度为O(m+n)。
暴力匹配
- 第一层循环为主字符串遍历匹配。
- 第二层循环为子字符串遍历匹配。
- 若子串中字符匹配失败,则进入下一轮主字符串匹配。
- 若子串中每个字符匹配成功,则返回子串在主串中的索引位置。
- 若主串遍历完后仍然未匹配,则返回-1表示匹配失败。
- 时间复杂度为O(m*n),m和n分别为主串和子串长度。
源码示例
#include <stdio.h>
#include <string.h>
// 原始主字符串
#define STR_TEXT "abaacababcac"
// 匹配子字符串
#define STR_PATTERN "ababc"
// 暴力匹配
int ori_match(char *text, char *pattern)
{
int i, j;
int tlen = strlen(text);
int plen = strlen(pattern);
// 循环主字符串匹配
for (i = 0; i < tlen - plen; i++) {
// 循环子字符串匹配
for (j = 0; j < plen; j++) {
// 字符不匹配
if (text[i+j] != pattern[j]) {
break;
}
}
// 子字符串匹配成功
if (j == plen) {
return i;
}
}
return -1;
}
int main()
{
printf("original match ret:%d\n", ori_match(STR_TEXT, STR_PATTERN));
return 0;
}
运行结果
[xiaofeng@localhost kmp]$ gcc main.c
[xiaofeng@localhost kmp]$ ./a.out
original match ret:5
[xiaofeng@localhost kmp]$
KMP匹配
- 需要提前根据子串初始化构造好next数组。
next[i]
的值等于P[0]...P[i - 1]
最长公共前后缀。next[i]
的值表示当第i个字符不匹配时,pi回溯的位置。
源码示例
#include <stdio.h>
#include <string.h>
// 原始主字符串
#define STR_TEXT "abaacababcac"
// 匹配子字符串
#define STR_PATTERN "ababc"
// 子字符串长度
#define PATTERN_LEN (sizeof(STR_PATTERN))
// next数组
int next_arr[PATTERN_LEN];
// 初始化next数组
void next_init(char *pattern, int next[]){
next[0] = -1;
int i = 0, j = -1;
while (i < strlen(pattern)) {
if (j == -1 || pattern[i] == pattern[j]) {
next[++i] = ++j;
printf("next[%d]=%d\n", i, next[i]);
} else {
j = next[j];
}
}
}
// KMP匹配
int kmp_match(char *text, char *pattern)
{
int i = 0, j = 0;
int tlen = strlen(text);
int plen = strlen(pattern);
while (i < tlen && j < plen) {
printf("text[%d]:%c, pattern[%d]:%c\n", i, text[i], j, pattern[j]);
if (j == 0 || text[i] == pattern[j]) {
i++;
j++;
} else {
j = next_arr[j];
}
}
// 子字符串匹配成功
if (j == plen) {
return i - j;
}
return -1;
}
int main()
{
next_init(STR_PATTERN, next_arr);
printf("kmp match ret:%d\n", kmp_match(STR_TEXT, STR_PATTERN));
return 0;
}
运行结果
[xiaofeng@localhost kmp]$ gcc main.c
[xiaofeng@localhost kmp]$ ./a.out
next[1]=0
next[2]=0
next[3]=1
next[4]=2
next[5]=0
text[0]:a, pattern[0]:a
text[1]:b, pattern[1]:b
text[2]:a, pattern[2]:a
text[3]:a, pattern[3]:b
text[3]:a, pattern[1]:b
text[3]:a, pattern[0]:a
text[4]:c, pattern[1]:b
text[4]:c, pattern[0]:a
text[5]:a, pattern[1]:b
text[5]:a, pattern[0]:a
text[6]:b, pattern[1]:b
text[7]:a, pattern[2]:a
text[8]:b, pattern[3]:b
text[9]:c, pattern[4]:c
kmp match ret:5
[xiaofeng@localhost kmp]$