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算法的C#代码如下:

public class SUNDAY

{

       public SUNDAY()

       {

       }

       public int QfindChr(string str, string Sfind)

       {

              int str_length = 0;

              int fin_length = 0;

 

              int find_count = 0;        // 初始化找到的次数

              int start = 0;                // 初始化开始位置

              int moveNum = 0;         // 初始化移动次数

 

              if (str.Length < Sfind.Length)

              {

                     return find_count;

              }

 

              str_length = str.Length;

              fin_length = Sfind.Length;

 

              while (start + fin_length <= str_length)

              {

                     moveNum++;

                     bool isfind = false;       // 是否在这次移动中找到

                     string s_temp = str.Substring(start, fin_length);

                     if (s_temp == Sfind)

                     {

                            find_count++;

                            start += fin_length;

                            isfind = true;

                     }

                     if (isfind == false)        // 如果没找到计算下次移动位置

                     {

                            int forwardPos = QfindPos(str, Sfind, start, fin_length);

                            start += forwardPos;

                     }

              }

              return find_count;

       }

      

       // 寻找字符在字符串的位置,没找到返回fin_length,找到返回位置

       public int QfindPos(string str, string find, int pos, int fin_length)

       {

              int returnPos = fin_length;

              int downPos = 1;

              char[] Schr = str.ToCharArray();

              char[] Sfin = find.ToCharArray();

              char chrFind = Schr[pos + fin_length - 1];     // 要找的字符

              if (fin_length > 1)

              {

                     for (int i = Sfin.GetLength(0) - 2; i >= 0; i--)

                     {

                            char Chtemp;

                            Chtemp = Sfin[i];

                            if (Chtemp == chrFind)

                            {

                                   returnPos = downPos;

                                   return returnPos;

                            }

                            eles

                                   downPos++;

                     }

              }

              return returnPos;

       }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值