字符串匹配算法 之 基于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...
给主人留下些什么吧!~~
评论热议
理论不再赘述,请参考算法导论一书,第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...
给主人留下些什么吧!~~
评论热议
相关文章推荐
- 有效运用auto_ptr
- SVN Externals Definitions[类似于软链接的功能]
- Linux创建与解压zip, tar, tar.gz,tar.bz2文件
- static_cast 与reinterpret_cast
- ACE_Task::putq
- goagent使用步骤
- 详谈高性能UDP服务器的开发
- Qt中findChildren返回值不对
- Why does the PDB format change every release?
- mysql_query与 mysql_real_query区别
- java.lang.UnsatisfiedLinkError: D:\Tomcat\apache-tomcat-7.0.37\bin\tcnative-1.dll: Can't load AMD 6
- 如何把Backtrack 5安装到U盘/Backtrack 4安装方法
- FreeBSD:像Linux下一样使用vim
- vi查找替换命令详解
- gcc多版本切换
- Centos 5.5升级Python到2.7版本
- 一个游戏程序员的学习资料
- VC编译nginx
- JNI和JNA性能比较
- JDK String 源码学习,这个构造方法写的有点逻辑不太清晰