[笔记-柔性字符串匹配]Shift-And与Shift-Or

Shift-And 和 KMP一样都是基于前缀搜索的方法,复杂度为O(n);

《柔性字符串匹配》:

  "只有当模式串小于8时,KMP才比基于后缀和基于子串的搜索方法有效。而在这个范围内,Shift-And算法和Shift-Or算法能够在所有机器上运行,速度至少是Knuth-Morris-Pratt的两倍,并且更易于实现。"

Shift-And对字母表中的每个字符构造一个位序列,根据下面的公式更新匹配状态D:

D = ((D<<1) | 0^{m-1}1) & B[t_{i+1}];

B[t_{i+1}]是字符t_{i+1}的位序列,当D的第j位为1并且t_{i+1}与p_{j+1}相等时,D的第j+1位更新为1,上式中的位或是因为空串也是文本的后缀。

因为状态表中位序列的有效长度为模式串的长度,所以当模式串长度超过机器字长时,需要构造自定义类型(应该行得通)。

示例:

# include <stdio.h>
# include <string.h>

int b[128];   /* int型共32位,模式串不超过32位 */

int shift_and(char *p, char *t);
int shift_or(char *p, char *t);

int main()
{
    char s1[5000], s2[30];

    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);

    while (~scanf("%s%s", s1, s2))
    {
        printf("shirt-and : %d, shift-or : %d.\n", shift_and(s2, s1), shift_or(s2, s1));
    }

    return 0;
}

int shift_and(char *p, char *t)
{
    int n, m, i, d, f;

    n = strlen(p);
    m = strlen(t);
    memset(b, 0, sizeof(b));
    for (i = 0; i < n; ++i)
    {
        b[p[i]] |= 0x1<<i;
    }

    d = 0;
    f = 0x1 << (n-1);
    for (i = 0; i < m; ++i)
    {
        d = ((d<<1) | 0x1) & b[t[i]];
        if (d & f) return i-n+1;    /* 可以根据需要返回第一次匹配结果 */
    }
    return -1;
}

int shift_or(char *p, char *t)
{
    int n, m, i, d, f;

    n = strlen(p);
    m = strlen(t);
    memset(b, 0xff, sizeof(b));
    for (i = 0; i < n; ++i)
    {
        b[p[i]] &= ~(0x1<<i);
    }
    d = 0xff;
    f = 0x1 << (n-1);
    for (i = 0; i < m; ++i)
    {
        d = (d<<1) | b[t[i]];        /* 可以根据需要返回第一次匹配结果 */
        if (!(d&f)) return i-n+1;
    }
    return -1;
}

posted on 2012-04-27 13:11  getgoing  阅读(749)  评论(0编辑  收藏  举报

导航