BM算法C语言实现

前些日子分析了一下BM算法,时间上断断续续的,效率很低,今天上午才算最后完工,关于BM算法我主要参考了以下内容:

1.http://ouyangjia7.iteye.com/blog/353137

2.http://blog.csdn.net/chong232/archive/2010/08/12/5806968.aspx

这两篇文章都写得很好,给我有很多帮助,但是看上面的源代码有一些地方我自己不理解,所以按照自己的思想改动了一些地方,现在将源代码贴下,我进行了简单的测试,全部正确,不过肯定测试的不完善,大家如果发现了错误请留言, 我好改正,大家对代码中有不明白的地方也可以留言,我可以帮忙说下,代码如下:<textarea cols="50" rows="15" name="code" class="cpp">#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; /* 函数:int* MakeSkip(char*,int) 母的:根据坏字符规则做预处理,建立一张坏字符表 表的长度由字符的规模而定, 如果只有字母则长度只有26, 如果是字母加数字长度就是26+10 参数: ptrn=&gt;模式串P pLen=&gt;模式串P长度 返回: int* - 坏字符表 */ int *MakeSkip(char* ptrn,int pLen) { int i; int len=pLen; char *p=ptrn; //为建立坏字符表,申请256个int的空间 int *skip=(int*)malloc(256*sizeof(int)); if(skip==NULL) { printf(&quot;malloc failed!&quot;); return 0; } //初始化坏字符表,256个单元全部初始化为pLen for(i=0;i&lt;256;i++) { *(skip+i)=pLen; } //赋值,从左到右遍历ptrn,这样如果一个字符出现两次,后面的覆盖前面的, //不在模式中出现的字符不用再赋值,它们使用默认值pLen。 while(pLen!=0) { *(skip+(int)*ptrn++)=--pLen; } return skip; } /* 函数:int *MakeShift(char*,int) 目的:根据好后缀原则做预处理,建立一张好后缀表 参数: ptrn=&gt;模式串P pLen=&gt;模式串P的长度 返回: int* :好后缀表 */ int *MakeShift(char *ptrn,int pLen) { //为好后缀表申请pLen个int的空间 //这样,第一个位置放置长度为1的后缀 int *shift=(int *)malloc(pLen*sizeof(int)); int *sptr=shift+pLen-1;//方便为好后缀表进行赋值的指针 char *pptr=ptrn+pLen-1;//记录好后缀表边界位置的指针 char c; //int i; if(shift==NULL) { fprintf(stderr,&quot;malloc failed!&quot;); return 0; } c=*(ptrn+pLen-1);//保存模式串中最后一个字符,因为要反复用到它 *sptr=1;//以最后一个字符为边界时,移动距离设为1(因为要与坏字符规则比较,所以这个是个假设,1也是最小的移动距离) pptr--;//边界移动到倒数第二个字符 while(--sptr&gt;=shift)//该最外层循环完成给好后缀表中的每一个单元进行赋值的工作 { char *p1=ptrn+pLen-2,*p2,*p3; //该do...while循环完成以当前pptr所指向的字符为边界时,要移动的距离 do { while(p1&gt;=ptrn&amp;&amp;*p1--!=c);//该空循环,寻找与最后一个字符c匹配的字符所指向的位置 if(p1&lt;ptrn) { *sptr=pLen; break; } p2=ptrn+pLen-2; p3=p1; while(p3&gt;=ptrn&amp;&amp;*p3--==*p2--&amp;&amp;p2&gt;=pptr);//该空循环,判断在边界内字符串匹配到什么位置 if(p2&lt;pptr) { if(*++p3==*++p2) { *sptr=p2-p3; break; } if(*p2==*p3) { continue; } } if(p3&lt;ptrn) { *sptr=p2-p3; break; } }while(p3&gt;=ptrn); pptr--;//边界继续向前移动 } return shift; } /* 函数:int* BMSearch(char*,int ,char*,int,int*,int*) 目的:判断文本串是否包含模式串P 参数: buf-&gt;文本串T blen-&gt;文本串T长度 ptrn-&gt;模式串P长度 plen-&gt;模式串P长度 skip-&gt;坏字符表 shift-&gt;好后缀表 返回: int-&gt;1表示成功(文本串包含模式串),0表示失败(文本串不包含模式串) */ int BMSearch(char *buf,int blen,char *ptrn,int plen,int *skip,int *shift) { int b_idx=plen; if(plen==0) { return 1; } while(b_idx&lt;=blen)//计算字符串是否匹配到了尽头 { int p_idx=plen,skip_stride,shift_stride; int i=0; int temp=b_idx;//是为了不改动b_idx的值,b_idx将来用于计算移动的距离 while(buf[--temp]==ptrn[--p_idx])//开始匹配 { i++; if(p_idx==0) { fprintf(stderr,&quot;match at %d!&quot;,b_idx); return 1; } } printf(&quot;i:%d/tbad:%c/n&quot;,i,buf[temp]); skip_stride=skip[(unsigned char)buf[temp]]-i;//根据坏字符规则计算跳跃的距离 shift_stride=shift[p_idx]; printf(&quot;b_idx:%d 1:%d 2:%d/n&quot;,b_idx,skip_stride,shift_stride); b_idx+=(skip_stride&gt;shift_stride)?skip_stride:shift_stride;//取最大者 } return 0; } int main() { char *buf=&quot;bcczcsabcd&quot;; char *ptrn=&quot;abc&quot;; int *skip=NULL; int *shift=NULL; fprintf(stderr,&quot;plen=%d!/n&quot;,strlen(ptrn)); skip=MakeSkip(ptrn,strlen(ptrn)); shift=MakeShift(ptrn,strlen(ptrn)); BMSearch(buf,strlen(buf),ptrn,strlen(ptrn),skip,shift); return 1; }</textarea>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值