KMP算法要解決的問題就是在字符串(也叫主串)中的模式(pattern)定位問題。說簡單點就是我們平時常說的關鍵字搜索。模式串就是關鍵字(接下來稱它爲T),如果它在一個主串(接下來稱爲S)中出現,就返回它的具體位置,否則返回-1(常用手段)。
假如是在串“SSSSSSSSSSSSSA”中查找“SSSSB”,設置兩個指針i,j,比較到最後一個才知道不匹配,然後其中的i回溯,這個的效率是顯然是最低的。大牛們是無法忍受“暴力破解”這種低效的手段的,於是他們研究出了KMP算法,其思想就如同我們上邊所看到的一樣:“利用已經部分匹配這個有效信息,保持i指針不回溯,通過修改j指針,讓模式串儘量地移動到有效的位置。”所以,整個KMP的重點就在於當某一個字符與主串不匹配時,我們應該知道j指針要移動到哪?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//打印一個數組
void print_array(int *a, int len)
{
int i;
for (i = 0; i < len; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
int str_index(const char *s, const char *t, int pos)
{
int i = pos;
int j = 0;
while (s[i] != '\0' && t[j]!= '\0')
{
if (s[i] == t[j])
{
i++;
j++;
}else
{
i = i - j + 1;
j = 0;
//printf("%d\n", i);
}
}
if (t[j] == '\0')
{
return i - j;
}else
{
return -1;
}
}
void get_next(const char *t, int *next, int len)
{
int j = 0;
int k = -1;
next[j] = -1;
while (t[j] != '\0')
{
if (k == -1 || t[j] == t[k])
{
next[++j] = ++k;
}else
{
k = next[k];
}
}
}
void get_next2(const char *t, int *next, int len)
{
int j = 0;
int k = -1;
next[j] = -1;
while (t[j] != '\0')
{
if (k == -1 || t[j] == t[k])
{
++j;
++k;
if (t[j] == t[k])
{
next[j] = next[k];
}else
{
next[j] = k;
}
}else
{
k = next[k];
}
}
}
int str_index_kmp(const char *s, const char *t, int pos)
{
int i = pos;
int j = 0;
int len = strlen(t);
int *next = (int *)malloc(sizeof(int) * (len + 1));
if (next == NULL)
{
printf("malloc failed\n");
exit(1);
}
get_next(t, next, len);
print_array(next, len);
get_next2(t, next, len);
print_array(next, len);
while (s[i] != '\0' && t[j]!= '\0')
{
if (s[i] == t[j])
{
i++;
j++;
}else if (j == 0)
{
i++;
}else
{
j = next[j];
printf("%d\n", i);
}
}
free(next);
if (t[j] == '\0')
{
return i - j;
}else
{
return -1;
}
}
int main()
{
int pos;
char buf[20] = "ABACCCCABABCDHI";
const char *t = "ABAB";
pos = str_index(buf, t, 0);
if (pos > 0)
{
printf("%s\n", buf + pos);
}
pos = str_index_kmp(buf, t, 0);
if (pos > 0)
{
printf("%s\n", buf + pos);
}
return 0;
}