我得承认,我对KMP的理解没有达到百分百,所以在阐述解释时都不能将KMP算法的妙处讲清楚。

 

一、实现思想

  •   通过对子串每一个字符进行扫描,会得出一个数组,这个数组可以用来帮助主串和子串比较时跳跃式前进(避免了一些不必要的比较)
  •   还是看图理解一下吧。(真的讲不清楚)

 

二、图例实现

 

  BF表现出来的缺点

 

 

   KMP算法

 

 

 

 

三、代码实现

  了解自身结构的函数,有了这个我们就可以知道在比较发生不匹配时可以跳过哪些,或者说是否要从头开始。这个函数我是看着课本的数学关系写出来的,所以我也解释不清。

 1 //得到next数组          这个函数就是用来了解自身结构的,但是妙处我描述不清楚,忏愧。
 2 int *find_next(char t[])
 3 {
 4     int len = strlen(t);
 5 
 6     int *next = new int[len]; //建立在堆区的next数组
 7 
 8     for (int i = 0; t[i] != '\0'; i++)
 9     {
10 
11         if (i == 0)
12             next[i] = -1;
13         else if (i == 1)
14             next[i] = 0;
15         else
16             for (int p_start = i - 1; p_start > 0; p_start--) //b部分的起点总是0,p部分的终点总是i-1,p_start作为p数组的起点
17             {
18                 // int flag = 0;        //flag是b数组的长度                //原来我能够写出来完全是因为书本的公式,原来我还没有理解的
19                 int a = 0;           //a先是作为b数组的起点,然后自增到终点
20                 int b = i - p_start; //b先是作为q数组的起点,然后自增到终点
21 
22                 while (t[a] == t[b] && b <= i - 1)
23                 {
24                     // flag++;
25                     a++;
26                     b++;
27                 }
28                 if (b == p_start) //这里的一些数字关系真的是太妙了,我很难解释清楚
29                 {
30                     next[i] = p_start;
31                     break;
32                 }
33                 else
34                     next[i] = 0;
35             }
36     }
37     return next;
38 }

  

  KMP执行

 1 //KMP实现               有了那个next数组,我们就可以知道哪些是可以跳过的
 2 int KMP(char s[], char t[])
 3 {
 4     int *next = find_next(t);
 5     int i = 0;
 6     int j = 0;
 7     int begin = i;
 8     while (s[i] != '\0' && t[j] != '\0')
 9     {
10         if (s[i] == t[j])
11         {
12             i++;
13             j++;
14         }
15         else
16         {
17             begin = begin + j - next[j];
18             j = next[j];
19         }
20         if (j == -1)
21         {
22             i++;
23             j++;
24             begin = i;
25         }
26     }
27     return begin;
28 }

  

 全部代码

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 //得到next数组          这个函数就是用来了解自身结构的,但是妙处我描述不清楚,忏愧。
 4 int *find_next(char t[])
 5 {
 6     int len = strlen(t);
 7 
 8     int *next = new int[len]; //建立在堆区的next数组
 9 
10     for (int i = 0; t[i] != '\0'; i++)
11     {
12 
13         if (i == 0)
14             next[i] = -1;
15         else if (i == 1)
16             next[i] = 0;
17         else
18             for (int p_start = i - 1; p_start > 0; p_start--) //b部分的起点总是0,p部分的终点总是i-1,p_start作为p数组的起点
19             {
20                 // int flag = 0;        //flag是b数组的长度                //原来我能够写出来完全是因为书本的公式,原来我还没有理解的
21                 int a = 0;           //a先是作为b数组的起点,然后自增到终点
22                 int b = i - p_start; //b先是作为q数组的起点,然后自增到终点
23 
24                 while (t[a] == t[b] && b <= i - 1)
25                 {
26                     // flag++;
27                     a++;
28                     b++;
29                 }
30                 if (b == p_start) //这里的一些数字关系真的是太妙了,我很难解释清楚
31                 {
32                     next[i] = p_start;
33                     break;
34                 }
35                 else
36                     next[i] = 0;
37             }
38     }
39     return next;
40 }
41 
42 //KMP实现               有了那个next数组,我们就可以知道哪些是可以跳过的
43 int KMP(char s[], char t[])
44 {
45     int *next = find_next(t);
46     int i = 0;
47     int j = 0;
48     int begin = i;
49     while (s[i] != '\0' && t[j] != '\0')
50     {
51         if (s[i] == t[j])
52         {
53             i++;
54             j++;
55         }
56         else
57         {
58             begin = begin + j - next[j];
59             j = next[j];
60         }
61         if (j == -1)
62         {
63             i++;
64             j++;
65             begin = i;
66         }
67     }
68     return begin;
69 }
70 int main(void)
71 {
72     char s[] = "ababadababac";
73     char t[] = "ababac";
74     int location = KMP(s, t);
75     printf("location = %d\n", location);
76     for (int i = 0; i < strlen(t); i++)
77     {
78         printf("%c  ", s[location]);
79         location++;
80     }
81     return 0;
82 }
83 /* 
84 输出
85 ————————————————————————
86 location = 6
87 a  b  a  b  a  c 
88 ————————————————————————
89  */
全部代码

 

四、总结

  这次虽然没能够完全理解KMP算法,但是对基本原理的印象加深了许多,并且意识到课本真的很厉害,虽然不能够很通俗易懂,但是该有的知识点都不会漏。

posted on 2020-08-30 23:17  Coderon  阅读(163)  评论(0编辑  收藏  举报