为什么使用'in'运算符进行子字符串搜索比使用KMP算法更快?

时间:2019-04-06 06:03:58

标签: python string algorithm

我遇到了用于子字符串搜索的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的字符串存储方式所致。

1 个答案:

答案 0 :(得分:1)

正如对该问题的评论中所建议的那样,内部字符串搜索算法在最佳情况下比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