您的位置:首页 > 其它

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

2016-01-25 16:40 239 查看
原文:http://www.91linux.com/html/article/program/cpp/20081017/13581.html

理论不再赘述,请参考算法导论一书,第32章32.3节利用有限自动机进行字符串匹配,本文主要给出了C语言的具体实现,关键地方都加上了注释。

#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;

}



阅读(969) | 评论(0) | 转发(1) |

0
上一篇:linux c/c++ GDB教程详解

下一篇:有效运用auto_ptr

相关热门文章

CU博客改版登录口说明...

如何利用客户端在CU发博客...

CU博客改版反馈意见

新版博文改进的一些功能...

ChinaUnix新博客正式上线,欢...

linux dhcp peizhi roc

关于Unix文件的软链接

求教这个命令什么意思,我是新...

sed -e "/grep/d" 是什么意思...

谁能够帮我解决LINUX 2.6 10...

给主人留下些什么吧!~~

评论热议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: