sunday 算法python实现

同为字符串查找的算法, Sunday真的比KMP简单太多了。

理解也很简单:

下面的文字可能比较难理解, 可以参考这个博主的博客理解
[字符串匹配——Sunday算法]https://blog.csdn.net/q547550831/article/details/51860017
假设有 字符串 A, 待比较字符串 B, 需要查找 A是否包含B。

  1. 对齐A的i位置和B的0位置, i从0开始。

  2. 如果A[i] 元素和B[0]相同,就继续比较A的下一个元素和B的下一个值,比较len(B)次, 就是看A这段字符串是不是B, 如果是就退出结束了。当然事情可能没这么简单, 如果不是,我们就得把B往后移动, 对齐到A的后面位置去。暴力方法的话, 是B每次往后移动一个位置,跟A比较一次。 KMP/BM/Sunday 这些算法都是计算位移的, 即尽可能多的跳过无用的元素, 减少比较的次数。

  3. 如果在第二步从i到i+len(B)-1的比较过程中有一个位置不相同,就直接去看 A[i + len(B)]是否在B中。 如果不同, 说明什么? 此时,我们已知对齐到i位置时的A跟B不相同了, 这下好了,i+len(B)的位置也不同, 我们本来是应该接着从i+1位置对齐开始比较的, 这下没必要了。 因为假设B出现在A的i+1开始的位置,则A[i+len(B)]这个值一定会出现在B中(因为从A的i+1开始取的这段len(B)长的字符串肯定会越过A的i+len(B)的位置, i+1+len > i+len)。 然而, 我们已经知道A[i+len(B)]不在B中了, 所以反证A[i+1]到A[i+len(B)] 这一大块肯定都不包含B,都可以跳过去了。然后,又回到了步骤1。

  4. 当然, 上一步也可能A[i+len(B)] 就在B中, 假设出现在B的倒数第x个位置。 这说明可能从i+1开始, A的字符串就包含B了。 这里,我们也不用一步步往后移动了, 直接把A的i+len(B)位置跟B的 x位置对齐不就行了吗。 此时再判断A这段是否跟B相同。 这样其实又回到了步骤3、4, 循环往复。

  5. 退出条件是直到A中找到了B或者找到了最后也没找到, 最后这段只要比较到两个字符串尾巴对齐就可以了, 即len(A) - len(B)的位置。

def sunday_find(src, dst):
    len_src = len(src)
    len_dst = len(dst)
    i = 0
    while i < len_src - len_dst + 1:
        flag = 0
        shift = len_dst
        for j in range(0, len_dst):
            if src[i+j] != dst[j]:
                flag = -1
                break

        if flag == 0:
            return i

        p = dst.rfind(src[i+shift])
        if p == -1:
            shift = len_dst + 1
        else:
            shift = len_dst - p

        i = i + shift

    return -1


if __name__ == "__main__":
    text = "here_examplfe_v_example"
    pattern = "ple"
    pos = sunday_find(text, pattern)
    print pos

你可能感兴趣的:(算法)