无双客栈

symbian linux e17 vim

无双: 注释
上面的算法对于模式串的匹配都是从左到右的 如果从右向左进行匹配的话 应该可以得到更大的移动量
boyer-moore算法是从右向左移动的例子
算法的介绍可以看这里
http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides03.pdf
或是相关的算法书(本文中引用了 数据结构与算法 java实现第二版的内容)

BM算法的要点:
假设模式串是P 主串是T, m=strlen(P),n=strlen(T)
1 从左向右移动模式串
2 对于模式串的匹配, 从右向左检查, 也就是P[m-1],p[m-2]...
3 当发现不匹配时, 使用好后缀和/或坏字符来决定模式串移动的距离 通常同时使用两个来加快查找速度

 当发现一个不匹配时 如下:
Consider a mismatch at P[n - 5]:
T: mahtava       talomaisema omalomailuun
P:maisemaomaloma
上面 m != t ,
这时 T 中的 t字符叫做坏字符
P 中的字符 "
aloma" 叫做好后缀
坏字符算法:
当出现一个坏字符时, BM算法向右移动模式串, 让模式中最靠右的对应字符与坏字符相对  然后继续匹配
好后缀算法:
如果程序匹配了一个好后缀, 并且在模式中还有另外一个相同的后缀, 那把下一个后缀移动到当前后缀位置(类似KMP 只是KMP是从左向右移动)
BM算法在查找开始时 先根据 模式串中所有字符建立一个坏字符表
然后创建一张好后缀表
具体的可以看上面介绍的pdf文件
下面是代码


/*
 * =====================================================================================
 *
 *        Filename:  bmtest.cpp
 *
 *     Description:  
 *
 *         Version:  1.0
 *         Created:  03/24/06 14:25:58 China Standard Time
 *        Revision:  none
 *        Compiler:  gcc
 *
 *          Author:  Zhonglei Li (), Zhonglei_Li@trendmicro.com.cn
 *         Company:  Trend Micro Incorporated
 *
 * =====================================================================================
 */
#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;


#define PatternStr      "gcagagag"//"gcagagag"
#define MainStr         "gcatcgcagagagtatacagtacg"
#define XSIZE           256
#define ASIZE           256
#define MAX(x,y)        (x) > (y)? (x):(y)

#define DUMP(x)        printf ## x
#define DUMP_ARRAY(next,size)    do{        \
    printf("next:\n\t");            \
    for(int i =0;i<size;i++){            \
    printf("% 2d ",next[i]);        \
    }                        \
    printf("\n");}while(0)

void preBmBc(char *x, int m, int bmBc[]) {
    int i;

    for (i = 0; i < ASIZE; ++i)
        bmBc[i] = m;
    for (i = 0; i < m - 1; ++i)
        bmBc[x[i]] = m - i - 1;
}


//  生成每个边界的suffix值
//  suff[i] = 以i为边界, 与pattern x 的后缀匹配的最大长度
//  可以运行程序查看输出
void suffixes(char *x, int m, int *suff)
{
    suff[m - 1] = m;        //    最后一个字符匹配的是整个T串
    int f   = 0;        //    记录上次匹配发生时的边界
    int    g   = m - 1;        //    记录当前未匹配的位置
    int i   = m - 2;        //    当前的边界,用来计算suff[i]的值
    DUMP(("suffixes:%s:%d\n",x,m));

    for (i = m - 2; i >= 0; --i) {
    //printf("current i   %d | %d |%d        %s    |   %s\n",i,g,f,x+i,x+g);
    char    fmt[256];
    sprintf(fmt,">>>>>>\ti:%d g:%d f:%d\n%%%ds\n%%%ds\n",
        i,g,f,m+2+m,m+2+i+1);
    DUMP((fmt,x,x));
    //  如果利用上次的匹配结果
    //  可以利用上次匹配结果的条件是:
    //    当前部分前面已经检查过( i > g ,可见上次已经检查过i对应的字符)
    //    上次匹配时匹配了足够的suffix 这时认为 P[i -> f] = P[g -> m-1]
    //    可以利用相似来对 suff[i]做判断
    bool skip    = i > g;
    if( skip ){
        sprintf(fmt,"%%%ds    => suff[f]\n%%%ds    =>suff[%d]:%d < %d\n",
            m + 2 + f + 1,
            m + 2 + m - 1 - (f-i)+1,
            i + m - 1 - f,suff[i + m - 1 - f] , i - g);
        DUMP((fmt,x,x));
        if( suff[i + m - 1 - f] < i - g ){
        DUMP(("skip checking,use value[%d]\n",i + m - 1 - f));
        suff[i] = suff[i + m - 1 - f];
        }
        else
        skip = false;
    }
    if( !skip ){
        if (i < g)        g = i;    //  保证从最后开始匹配
        f = i;            //  记录这次开始匹配的位置
        const char*    p1  = x+g;
        const char* p2  = x + g + m - 1 - f;
        int        pos1    = g;
        int        pos2    = g + m - 1 - f;
        //    从当前边界开始,向前尽可能的匹配后缀
        while (g >= 0 && x[g] == x[g + m - 1 - f])
        --g;

        suff[i] = f - g;        //  记录匹配的后缀的长度
    }
    DUMP(("val[%d]: %d\n",i,suff[i]));
    }
}



void preBmGs(char *x, int m, int bmGs[]) {
    int i, j, suff[XSIZE];

    suffixes(x, m, suff);

    for (i = 0; i < m; ++i)
        bmGs[i] = m;
    j = 0;

    //  下面的两图图摘自数据结构 java实现第二版
/*
*          i < m-j-1(失配位置)
*          |
* 0           |        m-j-1            m-1
* |          |        |              |
* ............A#########***********************
*          |        |              |
*             |        <---- Suffix Size ----><------ GS Shift ------>
*          |        <---- SS[j] = j+1 ----><-------- m-j-1 ------->
*          |        |              |                  |
*            ***********************........................
*            |              |                  |
*            0              j                  m-1
*            <--<--<--<--<--<--< 自右向扫描 <--<--<--<--<--<
*
************************************************************************/
    for (i = m - 1; i >= -1; --i)
        if (i == -1 || suff[i] == i + 1){   
            //  如果前缀与后缀相匹配,那保存偏移到bmGs
        //  或是已到最后,把还没有设置的bmGs设置成m
            //  如果值已经设置,那不需要再设置一次,保证最靠右的匹配子串优先
            DUMP(("i: %d j: %d < %d suff[%d] = %d\n",i,j,m - 1 - i,i,suff[i]));
            for (; j < m - 1 - i; ++j)
                if (bmGs[j] == m){
                    bmGs[j] = m - 1 - i;
                    DUMP(("bmGs[%d] = %d,m:%d\n",j,m - 1 - i,m));
                }
        }
    //    上一步是为了保证每个字符都会引起移动, 并且移动是把最靠右的匹配串移支对应的串上
    //    下一步会设置失配量, 失配量是对应它后面的匹配块的,
    //    移动量是把后面的匹配块移动到对应的后缀中

/*
*    m-SS[j]-1(失配位置)
*        |
* 0        |m-SS[j]    m-1
* |        ||        |
* ....................A**********************
*        ||        |
*        |<--- Suffix Size ----><-- GS Shift ->
*        |<------- SS[j] ------><--- m-j-1 --->
*        ||        |    |
*        .....B**********************...............
*        |    |        |    |
*        0 j-SS[j]+1        j    m-1
*        >-->-->-->-->--> 自左向右扫描 --->-->-->-->
*
************************************************************************/
    //    设置失配位置的移动量
    for (i = 0; i <= m - 2; ++i){
        bmGs[m - 1 - suff[i]] = m - 1 - i;
        DUMP(("i: %d bmgs[%d] = %d\n",i,m - 1 - suff[i],bmGs[m - 1 - suff[i]]));
    }
}


void BM(char *x, int m, char *y, int n) {
    int i, j, bmGs[XSIZE], bmBc[ASIZE];

    /* Preprocessing */
    preBmGs(x, m, bmGs);
    preBmBc(x, m, bmBc);
    DUMP_ARRAY(bmGs,m);

    /* Searching */
    j = 0;
    while (j <= n - m) {
        for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i);
        if (i < 0) {
            printf("MATCH:%d\n",j);
            j += bmGs[0];
        }
        else
            j += MAX(bmGs[i], bmBc[y[i + j]] - m + 1 + i);
    }
}

int main()
{
    BM(PatternStr,strlen(PatternStr),MainStr,strlen(MainStr));
    printf("demo finish,press key to exit\n");
    getchar();
    return 0;
}

Trackback: http://tb.donews.net/TrackBack.aspx?PostId=790922


[点击此处收藏本文]  发表于2006年03月24日 7:59 PM




正在读取评论……

发表评论

大名:
网址:
验证码
评论 
   

news

导航

blog stats

文章

收藏

相册

BBS

linux

存档


正在读取评论……