字符串匹配算法 之 基于DFA(确定性有限自动机)

确定有限自动机定义:http://en.wikipedia.org/wiki/Deterministic_finite_automaton

自动机在字符串匹配中的应用

  1 #include<stdio.h>

  2 #include<string.h>

  3 #include<stdlib.h>

  4 #define ALPHABETLENGTH 53

  5 #define GETMIN(x,y) ((x)<=(y)?(x):(y))

  6  

  7 //判定pattern的前k个字符是不是(pattern的前q个字符加上字符a组成的)字符串的后缀

  8 int IsSuffix(char *pattern,int k,int q,char a);

  9 //创建自动机(二维数组),并且根据给定的pattern完成自动机的初始化

 10 void Create(int*** array,char *pattern);

 11 //根据创建的自动机进行模式匹配,并返回模式在给定文本中第一次出现的结束位置

 12 int DFAMatcher(char* T,int** array,char *pattern);

 13 //在程序结束时,将创建的自动机(二维数组)进行销毁

 14 void Delete(int*** array,char *pattern);

 15 //一个小函数,用来查找给定的字符a在预先设定的字母表中的位置

 16 int SearchChar(char a);

 17 //预先设定的字母表,包括26个大小写的字母以及一个空格,共53个字符

 18 char alphabet[ALPHABETLENGTH]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";

 19  

 20 /*

 21 *通过函数来进行二维数组的分配,需要用到三重指针,传进去的是一个指针数组的地址,

 22 *直接传指针数组的话会造成悬垂指针,数组的构建需要根据pattern来构建

 23 *二维数组实际上就相当于自动机(DFA)了

 24 */

 25 void Create(int*** array,char *pattern)

 26 {

 27     //临时变量

 28     int i,j,k;

 29     //pattern的长度

 30     int patternlength=strlen(pattern);

 31     //二位数组的行数等于pattern中字符数加1

 32     int x=strlen(pattern)+1;

 33     //二维数组的列数等于字母表中所有的字符个数,这里我采用的是26个小写字母加上26个大写字母

 34     int y=ALPHABETLENGTH;

 35     //开始分配二维数组的空间,如果分配失败的话则要撤销已分配的单元。这里分两种情况,

 36     //一种是一开始就没有空间可分配,另一种是分配了一部分以后空间不足。

 37     *array=(int**)malloc(sizeof(int)*x);

 38     if(NULL==array)

 39     {

 40         fprintf(stderr,"\nspace is not enough!\n");

 41         return;

 42     }

 43     for(i=0; i<x; i++)

 44     {

 45         if(((*array)[i]=(int*)malloc(sizeof(int)*y))==NULL)

 46         {

 47             while(--i>=0)

 48             {

 49                 free((*array)[i]);

 50             }

 51             free(*array);

 52             fprintf(stderr,"\nspace is not enough!\n");

 53             return;

 54         }

 55     }

 56     //下面开始初始化二维数组的自动机表了

 57     for(i=0; i<=patternlength; i++)

 58     {

 59         for(j=0; j<ALPHABETLENGTH; j++)

 60         {

 61             k=GETMIN(patternlength+1,i+2);

 62             do

 63             {

 64                 --k;

 65  

 66             }

 67             while(k>0 && !IsSuffix(pattern,k,i,alphabet[j]));

 68             (*array)[i][j]=k;

 69         }

 70     }

 71     for(i=0; i<patternlength+1; i++)

 72     {

 73         for(j=0; j<ALPHABETLENGTH; j++)

 74         {

 75             printf("%d ",(*array)[i][j]);

 76         }

 77         printf("\n");

 78     }

 79 }

 80  

 81 //为了实现Pk是Pqa的后缀,k和q是字符数组P的下标表示数组P的前k和前q个字符,a是一个字符表示连接在字符串Pq后面

 82 int IsSuffix(char *pattern,int k,int q,char a)

 83 {

 84     int cmp;

 85     char Q[q+1];

 86     Q[q]=a;

 87     strncpy(Q,pattern,q);

 88     cmp=strncmp(pattern,Q+q-(k-1),k);

 89     if(cmp==0)

 90     {

 91         return 1;

 92     }

 93     else

 94     {

 95         return 0;

 96     }

 97 }

 98  

 99 //查找字符变量a在字母表中的位置

100 int SearchChar(char a)

101 {

102     int i=0;

103     while(alphabet[i]!=a)

104     {

105         ++i;

106     }

107     if(i>(ALPHABETLENGTH-1))

108     {

109         i=-1;

110     }

111     return i;

112 }

113 //利用自动机进行匹配

114 int DFAMatcher(char* T,int** array,char *pattern)

115 {

116     int i;

117     int n=strlen(T);

118     int m=strlen(pattern);

119     int q=0;

120     int position=0;

121  

122     for(i=0; i<n; i++)

123     {

124         position=SearchChar(T[i]);

125         if(position<0)

126         {

127             fprintf(stderr,"字符[%c]不存在\n",T[i]);

128             return -1;

129         }

130         q=array[q][position];

131         if(q==m)

132         {

133             printf("find!\n");

134             break;

135         }

136     }

137     if(q!=m)

138     {

139         printf("unfind\n");

140         i=-1;

141     }

142     return i;//如果匹配成功返回pattern在字符串的结束位置,否则返回-1;

143 }

144 //程序结束进行销毁二维数组

145 void Delete(int*** array,char *pattern)

146 {

147     int i;

148     int m=strlen(pattern);

149     for(i=m; i>=0; i--)

150     {

151         free((*array)[i]);

152     }

153     free((*array));

154 }

155  

156 int main(void)

157 {

158     char a[100]="defabcababacaghijkl";

159     char b[10]="ababaca";

160     int **array;

161     int i;

162     printf("开始构建自动机:\n");

163     Create(&array,b);

164     printf("自动机构建完毕!\n");

165     int end=DFAMatcher(a,array,b);

166     int first=end-strlen(b)+1;

167     if(end>=0)

168     {

169         printf("输入字符串:%s\n",a);

170         printf("模式:%s\n",b);

171         printf("结果:\n");

172         printf("%s\n",a);

173         for(i=0; i<strlen(a); i++)

174         {

175             if(i==end || i==first)

176             {

177                 printf("|");

178             }

179             else

180             {

181                 printf(" ");

182             }

183         }

184         printf("\nEnd Position:%d",end);

185     }

186     else

187     {

188         printf("结果出错了!");

189     }

190     Delete(&array,b);

191     return 1;

192 }

代码参考:出处

你可能感兴趣的:(字符串)