模式匹配算法

1、基本概念:

  目标串:s

  模式串:t

  模式串第 j 个元素 :t[j]

 

2、BF算法:

  通过将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。 

 

3、KMP算法:

  通过利用已经部分匹配这个有效信息,保证 i 指针不回溯,通过修改 j 指针,让模式串尽量移动到有效位置。其中这个有效信息指的就是 next 数组和 nextval 数组。

3.1 next 数组手工求法

文字描述:

  这里规定 next[0] = -1 ;

  对于 next[j] ,考虑 j 之前的串,找出前缀和后缀相同的最长字串,设长度为 k ,则 next[j] = k 。

实例:

  模式串 t : abcaba

  比如求 next[5] ,考虑 abcab ,易知前缀和后缀相同的最长字串为 ab ,其长度为 2 ,故 next[5] = 2 。

3.2 nextval 数组手工求法

文字描述:

  这里同样规定 nextval[0] = -1;

  若 t[j] = t[next[j]] ,则 nextval[j] = nextval[next[j]] ,否则保持不变。

实例:

j 0 1 2 3 4 5 6
模式 t  a b c a b a a
next[j] -1 0 0 0 1 2 1
nextval[j] -1 0 0 -1 0 2 1

  比如求 nextval[4] ,首先 t[4] = b = t[next[4]] = t[1] ,则 nextval[4] = nextval[next[4]] = nextval[1] = 0 ;

  求 nextval[5] ,首先 t[5] = a =\= c = t[next[5]] = t[2] ,则 nextval[5] = next[5] = 2 。

 

4、完整代码及运行结果

  苦逼的代码:

  1 #include<stdio.h>
  2 #include <string.h>
  3 #define MaxSize 50
  4 typedef char ElemType;
  5 
  6 typedef struct {
  7     ElemType data[MaxSize];
  8     int length;
  9 } SqString;
 10 
 11 //BF 算法
 12 int BFIndex(SqString s, SqString t) {
 13     int i = 0, j = 0;
 14     while(i < s.length && j < t.length) {
 15         if (s.data[i] == t.data[j]) {
 16             i++;
 17             j++;
 18         } else {
 19             //目标串 s 指针 i 和模式串 t 指针 j 同步后移
 20             i = i - j + 1;
 21             j = 0;
 22         }
 23     }
 24     if (j >= t.length) {
 25         return i - t.length;
 26     } else {
 27         return -1;
 28     }
 29 }
 30 
 31 //计算 next 数组
 32 void GetNext(SqString t, int next[]) {
 33     int j = 0, k = -1;
 34     next[0] = -1;
 35     while(j < t.length) {
 36         if (k == -1 || t.data[j] == t.data[k]) {
 37             j++;
 38             k++;
 39             next[j] = k;
 40         } else {
 41             k = next[k];
 42         }
 43     }
 44 }
 45 //依据 next 数组实现的 KMP 算法
 46 int KMPIndex(SqString s, SqString t) {
 47     int i = 0, j = 0;
 48     int next[MaxSize];
 49     GetNext(t, next);
 50     while(i < s.length && j < t.length) {
 51         if (j == -1 || s.data[i] == t.data[j]) {
 52             i++;
 53             j++;
 54         } else {
 55             //模式串 t 指针 j 后移
 56             j = next[j];
 57         }
 58     }
 59     if (j >= t.length) {
 60         //返回模式串 t 所在位置物理下标
 61         return i - t.length;
 62     } else {
 63         //匹配失败返回 -1
 64         return -1;
 65     }
 66 }
 67 
 68 //计算 nextval 数组
 69 void GetNextval(SqString t, int nextval[]) {
 70     int j = 0, k = -1;
 71     nextval[0] = -1;
 72     while(j < t.length) {
 73         if (k == -1 || t.data[j] == t.data[k]) {
 74             j++;
 75             k++;
 76             if (t.data[j] != t.data[k]) {
 77                 nextval[j] = k;
 78             } else {
 79                 nextval[j] = nextval[k];
 80             }
 81         } else {
 82             k = nextval[k];
 83         }
 84     }
 85 }
 86 //根据 nextval 数组实现的 KMP 算法
 87 int KMPIndex1(SqString s, SqString t) {
 88     int i = 0, j = 0;
 89     int nextval[MaxSize];
 90     GetNextval(t, nextval);
 91     while(i < s.length && j < t.length) {
 92         if (j == -1 || s.data[i] == t.data[j]) {
 93             i++;
 94             j++;
 95         } else {
 96             //模式串 t 指针 j 后移
 97             j = nextval[j];
 98         }
 99     }
100     if (j >= t.length) {
101         //返回模式串 t 所在位置物理下标
102         return i - t.length;
103     } else {
104         //匹配失败返回 -1
105         return -1;
106     }
107 }
108 
109 //将字符串数组赋值给 SqString 类型的字符串
110 void StrAssign(SqString &s, char csrt[]) {
111     int i;
112     for (i = 0; csrt[i] != '\0'; i++) {
113         s.data[i] = csrt[i];
114     }
115     s.length = i;
116 }
117 
118 int main(int argc, char const *argv[]) {
119     SqString s, t;
120     StrAssign(s, (char *)"awzabcabaawanghizhi");
121     StrAssign(t, (char *)"abcabaa");
122 
123     int next[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
124     int nextval[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
125     GetNext(t, next);
126     GetNextval(t, nextval);
127 
128     printf("next and nextval:\n");
129     printf("j\t\t");
130     for (int i = 0; i < t.length; ++i) {
131         printf("%d\t", i);
132     }
133     printf("\nt[j]\t\t");
134     for (int i = 0; i < t.length; ++i) {
135         printf("%c\t", t.data[i]);
136     }
137     printf("\nnext[j]\t\t");
138     for (int i = 0; i < t.length; ++i) {
139         printf("%d\t", next[i]);
140     }
141     printf("\nnextval[j]\t");
142     for (int i = 0; i < t.length; ++i) {
143         printf("%d\t", nextval[i]);
144     }
145     printf("\n\n");
146 
147     printf("BFIndex = %d\n", BFIndex(s, t));
148     printf("KMPIndex = %d\n", KMPIndex(s, t));
149     printf("KMPIndex1 = %d\n", KMPIndex1(s, t));
150     return 0;
151 }
看着我的笑脸*^_^*,点一下塞~

  运行结果:

next and nextval:
j               0       1       2       3       4       5       6
t[j]            a       b       c       a       b       a       a
next[j]         -1      0       0       0       1       2       1
nextval[j]      -1      0       0       -1      0       2       1

BFIndex = 3
KMPIndex = 3
KMPIndex1 = 3

 

5、总结

  花费了我两天中部分时间整理了模式匹配,只能算是初步掌握了这些,远达不到应用的地步。。。

  之后的时间可能会整理一些应用样例。。。

 

posted @ 2018-09-01 22:41  流光易染  阅读(2511)  评论(0编辑  收藏  举报