理论不再赘述,请参考算法导论一书,第32章32.3节利用有限自动机进行字符串匹配,本文主要给出了C语言的具体实现,关键地方都加上了注释。
该程序在CodeBlocks 10.05下调试通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | #include<stdio.h> #include<string.h> #include<stdlib.h> #define ALPHABETLENGTH 53 #define GETMIN(x,y) ((x)<=(y)?(x):(y)) //判定pattern的前k个字符是不是(pattern的前q个字符加上字符a组成的)字符串的后缀 int IsSuffix( char *pattern, int k, int q, char a); //创建自动机(二维数组),并且根据给定的pattern完成自动机的初始化 void Create( int *** array, char *pattern); //根据创建的自动机进行模式匹配,并返回模式在给定文本中第一次出现的结束位置 int DFAMatcher( char * T, int ** array, char *pattern); //在程序结束时,将创建的自动机(二维数组)进行销毁 void Delete( int *** array, char *pattern); //一个小函数,用来查找给定的字符a在预先设定的字母表中的位置 int SearchChar( char a); //预先设定的字母表,包括26个大小写的字母以及一个空格,共53个字符 char alphabet[ALPHABETLENGTH]= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ " ; /* *通过函数来进行二维数组的分配,需要用到三重指针,传进去的是一个指针数组的地址, *直接传指针数组的话会造成悬垂指针,数组的构建需要根据pattern来构建 *二维数组实际上就相当于自动机(DFA)了 */ void Create( int *** array, char *pattern) { //临时变量 int i,j,k; //pattern的长度 int patternlength= strlen (pattern); //二位数组的行数等于pattern中字符数加1 int x= strlen (pattern)+1; //二维数组的列数等于字母表中所有的字符个数,这里我采用的是26个小写字母加上26个大写字母 int y=ALPHABETLENGTH; //开始分配二维数组的空间,如果分配失败的话则要撤销已分配的单元。这里分两种情况, //一种是一开始就没有空间可分配,另一种是分配了一部分以后空间不足。 *array=( int **) malloc ( sizeof ( int )*x); if (NULL==array) { fprintf (stderr, "\nspace is not enough!\n" ); return ; } for (i=0; i<x; i++) { if (((*array)[i]=( int *) malloc ( sizeof ( int )*y))==NULL) { while (--i>=0) { free ((*array)[i]); } free (*array); fprintf (stderr, "\nspace is not enough!\n" ); return ; } } //下面开始初始化二维数组的自动机表了 for (i=0; i<=patternlength; i++) { for (j=0; j<ALPHABETLENGTH; j++) { k=GETMIN(patternlength+1,i+2); do { --k; } while (k>0 && !IsSuffix(pattern,k,i,alphabet[j])); (*array)[i][j]=k; } } for (i=0; i<patternlength+1; i++) { for (j=0; j<ALPHABETLENGTH; j++) { printf ( "%d " ,(*array)[i][j]); } printf ( "\n" ); } } //为了实现Pk是Pqa的后缀,k和q是字符数组P的下标表示数组P的前k和前q个字符,a是一个字符表示连接在字符串Pq后面 int IsSuffix( char *pattern, int k, int q, char a) { int cmp; char Q[q+1]; Q[q]=a; strncpy (Q,pattern,q); cmp= strncmp (pattern,Q+q-(k-1),k); if (cmp==0) { return 1; } else { return 0; } } //查找字符变量a在字母表中的位置 int SearchChar( char a) { int i=0; while (alphabet[i]!=a) { ++i; } if (i>(ALPHABETLENGTH-1)) { i=-1; } return i; } //利用自动机进行匹配 int DFAMatcher( char * T, int ** array, char *pattern) { int i; int n= strlen (T); int m= strlen (pattern); int q=0; int position=0; for (i=0; i<n; i++) { position=SearchChar(T[i]); if (position<0) { fprintf (stderr, "字符[%c]不存在\n" ,T[i]); return -1; } q=array[q][position]; if (q==m) { printf ( "find!\n" ); break ; } } if (q!=m) { printf ( "unfind\n" ); i=-1; } return i; //如果匹配成功返回pattern在字符串的结束位置,否则返回-1; } //程序结束进行销毁二维数组 void Delete( int *** array, char *pattern) { int i; int m= strlen (pattern); for (i=m; i>=0; i--) { free ((*array)[i]); } free ((*array)); } int main( void ) { char a[100]= "defabcababacaghijkl" ; char b[10]= "ababaca" ; int **array; int i; printf ( "开始构建自动机:\n" ); Create(&array,b); printf ( "自动机构建完毕!\n" ); int end=DFAMatcher(a,array,b); int first=end- strlen (b)+1; if (end>=0) { printf ( "输入字符串:%s\n" ,a); printf ( "模式:%s\n" ,b); printf ( "结果:\n" ); printf ( "%s\n" ,a); for (i=0; i< strlen (a); i++) { if (i==end || i==first) { printf ( "|" ); } else { printf ( " " ); } } printf ( "\nEnd Position:%d" ,end); } else { printf ( "结果出错了!" ); } Delete(&array,b); return 1; } |
(转载时请注明作者和出处。未经许可,请勿用于商业用途)
更多文章请访问我的Blog: http://www.cnblogs.com/alexqdh
更多文章请访问我的Blog: http://www.cnblogs.com/alexqdh
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步