【问题标题】:Why is substring searching using 'in' operator, faster than using KMP algorithm?为什么使用“in”运算符搜索子字符串比使用 KMP 算法更快?
【发布时间】:2019-04-06 06:03:58
【问题描述】:

我遇到了用于子字符串搜索的 KMP 算法,并在 python 中实现了它。后来,我发现in 运算符也可以用来解决这个问题,我决定比较它们的性能。令我惊讶的是,in 比 KMP 算法快得多,我决定仔细研究一下in

我发现in 在一个字符串中实现了__contains__ 方法,该方法用于Datamodel doc 中建议的包含检查。但无法进一步了解为什么它更快。

这是我的 KMP 算法实现:

def lps(pattern):
    start_ind = 0
    lps_list = [0]
    for j in pattern[1:]:
        if(j == pattern[start_ind]):
            lps_list.append(start_ind)
            start_ind += 1
        else:
            start_ind = 0
            lps_list.append(start_ind)
    return lps_list
def kmp(search, pattern):
    lps_list = lps(pattern)
    pat_ind = 0
    for j in search:
        if(pat_ind == len(pattern)):
            return True
        if(j == pattern[pat_ind]):
            pat_ind += 1
            continue
        while(j != pattern[pat_ind] and pat_ind != 0):
            pat_ind = lps_list[pat_ind - 1]
        if(pat_ind == 0 and j == pattern[pat_ind]):
                pat_ind += 1
    else:
        if(pat_ind == len(pattern)):
            return True
        return False

驱动程序块:

start = timeit.default_timer()
print('Found!!') if(kmp(search, pattern)) else print('Nope')
print(f'KMP algorithm: {(timeit.default_timer() - start):0.8e}')

start = timeit.default_timer()
print('Found!!') if(pattern in search) else print('Nope')
print(f'in operator: {(timeit.default_timer() - start):0.8e}')

测试用例和结果:

search = ''.join(['a' for _ in range(10000)] + ['b'])
pattern = ''.join(['a' for _ in range(1000)] + ['b'])
Found!!
KMP algorithm: 4.42536000e-03
Found!!
in operator: 3.72060003e-05

我预计 KMP 算法不会像结果显示的那么慢,因为它是一个不错的子字符串搜索算法。我不明白是不是,我的测试用例遗漏了一些东西,或者由于 Python 存储字符串的方式。

【问题讨论】:

  • 这是内置的一些历史背景:effbot.org/zone/stringlib.htm
  • 还请记住,内置函数是用 C 编写的,而 KMP 是用纯 Python 编写的(因为它被解释了,所以会产生很大的乘法性能损失)。
  • 你认为 Python 使用什么算法?见the source。以下是来自实施者的notes:“这排除了大多数标准算法(Knuth-Morris-Pratt 不是次线性的,Boyer-Moore 需要依赖于字母大小和模式大小的表格,大多数 Boyer-Moore 变体需要取决于图案大小等的表格。经过一些调整,我想出了 Boyer-Moore 的简化,并结合了 Horspool 和 Sunday 的想法。”
  • 如果您想从 Python 的 str.__contains__ 中查看最坏情况的行为,请尝试搜索 'a'*1000+'ba'。您的测试会将最简单的天真字符串搜索置于最坏情况下的性能,但 str.__contains__ 需要稍微困难的情况。
  • @NPE,没想到。这是有道理的。

标签: python string algorithm


【解决方案1】:

正如问题的 cmets 中所建议的,内部字符串搜索算法在最好的情况下比 KMP 算法更快,但在最坏的情况下也慢。最坏的情况很少见。这是一些background,以及它的实现的source code。而且它是用 C 实现的,这一事实使它更快。 下面是str.__contains__ 的最坏情况和结果:

search = 'a' * 10000000 + 'ba'
pattern = 'a' * 10000 + 'ba'
Found!!
KMP algorithm: 3.29188600e+00
Found!!
in operator: 3.85637655e+01

【讨论】:

    猜你喜欢
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 2016-03-03
    • 2013-01-15
    • 2011-08-15
    • 2017-02-10
    • 1970-01-01
    相关资源
    最近更新 更多