Sunday算法

 

Sunday算法是Daniel M.Sunday于1990年提出的一种比BM算法搜索速度更快的算法。其核心思想是:在匹配过程中,模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较,它在发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。

Sunday算法思想跟BM算法很相似,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。

例如我们要在"substring searching"查找"search",刚开始时,把子串与文本左边对齐:

s

u

b

s

t

r

i

n

g

 

s

e

a

r

c

h

i

n

g

s

e

a

r

c

h

 

 

 

 

 

 

 

 

 

 

 

 

 

结果在第二个字符处发现不匹配,于是要把子串往后移动。但是该移动多少呢?这就是各种算法各显神通的地方了,最简单的做法是移动一个字符位置;KMP是利用已经匹配部分的信息来移动;BM算法是做反向比较,并根据已经匹配的部分来确定移动量。这里要介绍的方法是看紧跟在当前子串之后的那个字符(上图中的'i')。

显然,不管移动多少,这个字符是肯定要参加下一步的比较的,也就是说,如果下一步匹配到了,这个字符必须在子串内。所以,可以移动子串,使子串中的最右边的这个字符与它对齐。现在子串'search'中并不存在'i',则说明可以直接跳过一大片,从'i'之后的那个字符开始作下一步的比较,如下图:

s

u

b

s

t

r

i

n

g

 

s

e

a

r

c

h

i

n

g

 

 

 

 

 

 

 

s

e

a

r

c

h

 

 

 

 

 

 

比较的结果,第一个字符就不匹配,再看子串后面的那个字符,是'r',它在子串中出现在倒数第三位,于是把子串向前移动三位,使两个'r'对齐,如下:

s

u

b

s

t

r

i

n

g

 

s

e

a

r

c

h

i

n

g

 

 

 

 

 

 

 

 

 

 

s

e

a

r

c

h

 

 

 

这次匹配成功了!回顾整个过程,我们只移动了两次子串就找到了匹配位置。可以证明,用这个算法,每一步的移动量都比BM算法要大,所以肯定比BM算法更快。

 

 

/* Sunday.h */

class Sunday 

{

public:

   Sunday();

   ~Sunday();

 

public:

    int find(const char* pattern, const char* text);

 

private:

    void preCompute(const char* pattern);

 

private:

    //Let's assume all characters are all ASCII

    static const int ASSIZE = 128;

    int _td[ASSIZE] ;

    int _patLength;

    int _textLength;

};

 

 

源文件

/* Sunday.cpp */

 

Sunday::Sunday()

{

}

 

Sunday::~Sunday()

{

}

 

void Sunday::preCompute(const char* pattern)

{

    for(int i = 0; i < ASSIZE; i++ ) 

        _td[i] = _patLength + 1;

 

    const char* p;

    for ( p = pattern; *p; p++)

        _td[*p] = _patLength - p - pattern)(;

}

 

int Sunday::find(const char* pattern, const char* text)

{

    _patLength = strlen( pattern );

    _textLength = strlen( text );

 

    if ( _patLength <= 0 || _textLength <= 0)

        return -1;

 

    preCompute( pattern );

 

    const char *t, *p, *tx = text;

 

    while (tx + _patLength <= text + _textLength) 

    {

        for (p = pattern, t = tx; *p; ++p, ++t)

        {

            if (*p != *t)

                break;

        }

        if (*p == 0)

            return tx-text;

        tx += _td[tx[_patLength]]; 

    }

    return -1;

}

 

简单测试下:

int main()

 

{

    char* text = "blog.csdn,blog.net";

    char* pattern = "csdn,blog"    ;

    Sunday sunday;

 

    printf("The First Occurence at: %d/n",sunday.find(pattern,text));

 

    return 1;

}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值