几种文本匹配算法速度比较

暴力法

def brute_force_search(string: str, pattern: str) -> int:
    """暴力匹配
    时间复杂度:O(m*n),空间复杂度:O(1)
    """
    n, m = len(string), len(pattern)
    if n >= m:
        for k in range(n - m + 1):
            i, j = k, 0
            while i < n and j < m and string[i] == pattern[j]:
                i = i + 1
                j = j + 1
            if j == m:
                return k
    return -1

kmp算法

def kmp_search(string: str, pattern: str) -> int:
    """kmp算法
    时间复杂度:O(m+n),空间复杂度:O(m)
    """
    n = len(string)
    m = len(pattern)
    next_pos = [0] * m
    i, j = 1, 0
    while i < m:
        if pattern[i] == pattern[j]:
            next_pos[i] = j + 1
            j += 1
            i += 1
        elif j != 0:
            j = next_pos[j - 1]
        else:
            next_pos[i] = 0
            i += 1
    i, j = 0, 0
    while i < n and j < m:
        if string[i] == pattern[j]:
            i += 1
            j += 1
        elif j != 0:
            j = next_pos[j - 1]
        else:
            i += 1
    return i - j if j == m else -1

Horspool算法

def horspool_search(string: str, pattern: str) -> int:
    """Boyer-Moore-Horspool算法
    时间复杂度:平均O(n),最坏O(n*m),最佳O(n/m),空间复杂度:O(m)
    """
    n, m = len(string), len(pattern)
    if m == 0:
        return 0
    if m > n:
        return -1
    bad_match_tb = {
     }
    # 不包含最后一个字符
    for i in range(m - 1):
        bad_match_tb[pattern[i]] = m - i - 1
    i = 0
    while i <= n - m:
        j = m - 1
        while j >= 0 and string[i + j] == pattern[j]:
            j -= 1
        if j == -1:
            return i
        # 如果该字符在模式串中未出现,返回m
        i += bad_match_tb.get(string[i + m - 1], m)
    return -1

Sunday算法

def sunday_search(string: str, pattern: str) -> int:
    """sunday算法
    时间复杂度:平均O(n),最坏O(n*m),最佳O(n/m),空间复杂度:O(m)
    """
    n, m = len(string), len(pattern)
    if m == 0:
        return 0
    if m > n:
        return -1
    # 事先计算模式串中每个最靠右的字符移动到末尾的距离
    shift_tb = {
     }
    for i in range(m):
        shift_tb[pattern[i]] = m - i
    i = 0
    while i <= n - m:
        j = 0
        # 不同于BM算法,这里从前往后匹配
        while string[i + j] == pattern[j]:
            j += 1
            if j >= m:
                return i
        k = i + m  # 当前模式串最后一个字符的下一个位置
        if k >= n:
            return -1
        # 如果k这个位置的字符再模式串中出现,则取事先计算的值,否则移动m+1
        i += shift_tb.get(string[k], m + 1)
    return -1

测试

以上不包括原始的Boyer-Moore算法,由于好后缀实现比较复杂,而且发现最后效果也不好,所以没有列出(也可能是我的代码问题)。当然,我也比较了python自带的string.find(pattern)方法。

import random
import string
def rand_string(length: int) -> str:
    """返回指定长度的随机字符串"""
    return ''.join(random.choices(string.printable, k=length))

取长度为10000000的随机字符串,长度为1000000的子串,分别放开头、中间、结尾测试结果如下(单位为秒):

brute force kmp Horspool Sunday find
开头 0.387 0.510 0.331 0.282 0.002
中间 1.839 1.343 0.349 0.314 0.006
结尾 2.148 2.098 0.369 0.327 0.011

结论:python自带的find方法很快,完。

你可能感兴趣的:(算法,字符串,python,horspool,sunday)