模式匹配算法


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、總結

  花費了我兩天中部分時間整理了模式匹配,只能算是初步掌握了這些,遠達不到應用的地步。。。

  之后的時間可能會整理一些應用樣例。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM