No.6Sunday算法的扩展以及python实现

什么是Sunday算法

  1. Sunday算法是是 Daniel M.Sunday 于 1990 年提出的一个字符串匹配算法,是由BM算法演变而来,有兴趣的盆友可以了解一下BM算法,但是不了解也不影响我们今天对Sunday算法的学习
  2. 说到字符串匹配算法,老规矩我们必须分清楚主串和模式串的概念,比如要在a=‘abbcf’,b=‘sjldfsdabbcfdsfs’,要在b中找a的,则a为模式串,b为主串
  3. Sunday 算法 与 KMP 算法 一样是从前往后匹配,在匹配失败时关注的是主串中参加匹配的最末位字符的下一位字符。
  如果该字符没有在模式串中出现则直接跳过,即移动位数 = 模式串长度 + 1。
  否则,其移动位数 = 模式串长度 - 该字符最右出现的位置(以0开始) = 模式串中该字符最右出现的位置到尾部的距离 + 1。

举个例子来理解一下它的操作过程。
假定现在要在主串substring searching xiaowu 中查找模式串 search 。

  • 刚开始时,把模式串与文本串左边对齐:
    在这里插入图片描述
    在这里插入图片描述
  • 结果发现在第 2 个字符处发现不匹配,不匹配时关注文本串中参加匹配的最末位字符的下一位字符,即绿色的字符 i,因为模式串 search 中并不存在 i,所以模式串直接跳过一大片,向右移动位数 = 匹配串长度 + 1 = 6 + 1 = 7,从 i 之后的那个字符(即字符 n)开始下一步的匹配,如下图:
    在这里插入图片描述
  • 结果第一个字符就不匹配,再看文本串中参加匹配的最末位字符的下一位字符,是 ‘r’ ,它出现在模式串中的倒数第 3 位,于是把模式串向右移动 3 位( r 到模式串末尾的距离 + 1 = 2 + 1 =3),使两个 ‘r’ 对齐,如下:
    在这里插入图片描述
  • 匹配成功

基于python的Sunday算法的实现

  1. 只找出第一次匹配到的字符串的第一个下标
def sunday_match_str(main_str, find_str):
    """
    :param main_str: 主串
    :param find_str: 模式串
    :return: 返回第一个匹配到模式串中第一个字符在主串中的下标
    """
    m, f = 0, 0
    m_len, f_len = len(main_str), len(find_str)
    while m < m_len:
        if main_str[m] == find_str[f]:
            m, f = m + 1, f + 1
            if f == f_len:
                return m - f_len  # 此时找到了第一个匹配到的下标
            continue
        else:
            flag = m - f + f_len
            if flag > m_len - 1:  # main_str下标越界,没有找到匹配的串
                return -1
            check_exits = find_str.rfind(main_str[flag])
            if check_exits != -1:  # 在find_str中有匹配
                jump = f_len - check_exits  # 移动的步长
                m, f = m - f + jump, 0
            else:  # 在find_str中无匹配
                jump = f_len + 1  # 移动的步长
                m, f = m - f + jump, 0
    else:
        return -1


main_st = 'substring searching xiaowu'
find_st = 'searching'
print(sunday_match_str('baa', 'aa'))
  1. 找出所有匹配到的字符串的第一个下标:
    比如:
  • main_st=‘aaabaaabaaaabaaaaab’,find_st=‘aa’
    对应的结果为:[0, 1, 4, 5, 8, 9, 10, 13, 14, 15, 16]
  • main_st=‘foobarfoobar’,find_st=‘foobar’
    对应的结果为:[0, 6]
def m_f_change(f_len, m, f, check_exits):
   if check_exits != -1:
       jump = f_len - check_exits
       m, f = m - f + jump, 0
   else:
       jump = f_len + 1
       m, f = m - f + jump, 0
   return m, f

def find_str_begin(main_str, find_str):
   m, f = 0, 0
   m_len, f_len, result = len(main_str), len(find_str), list()
   while m < m_len:
       if main_str[m] == find_str[f]:
           m, f = m + 1, f + 1
           if f == f_len:
               result.append(m - f_len)
               flag = m - f + f_len
               if flag > m_len - 1:
                   return result
               check_exits = find_str.rfind(main_str[flag])
               m, f = m_f_change(f_len,m,f,check_exits)
           continue
       else:
           flag = m - f + f_len
           if flag > m_len - 1:
               return result
           check_exits = find_str.rfind(main_str[flag])
           m,f=m_f_change(f_len,m,f,check_exits)
   else:
       return result
print(find_str_begin('substring searching xiaowu','searching'))
print(find_str_begin('baa','aa'))
print(find_str_begin('foobarfoobar', 'foobar'))
print(find_str_begin('aaabaaabb','aa'))

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值