【数据结构】串、KMP 算法 Python 版

    一、

    串就是字符串,本质上就是线性结构,其中可以存放各种字符,是线性表的一个具体表现形式。

    二、
    串表示法

    串的表示方法主要有顺序存储,包括预定长度的串(定长顺序表示)和可变长度的串(堆分配存储);还有链表表示方法,包括存储结点大小为1的表示,还有每一个链表结点存储k个字符的链表表示。

    链表表示法中,如果每一个结点存放一个字符的话,存储密度比较低,但是运算操作效率比较高;反之,每个节点都存储k个字符的话,操作起来会费劲一些,但是存储密度足够好。

    三、
    串的操作
    对串的操作和对链表的操作差不多,唯一的区别就是如果每个节点中存放了K个字符的话,就需要考虑不被k整除的串索引的情况了。

    主流语言中都有内置的串操作函数,这里也没必要再实现一遍串的数据结构了。但是串操作有一个和线性表很不同的就是串的模式匹配,更复杂的情况也就是正则表达式。

    正常的串模式匹配算法就是在主串中以此匹配模式串,如果匹配成功,则返回首个字符的串索引,如果匹配失败,就继续匹配下一个字符。但是这种最基本的方法效率并不高,时间复杂度 o(m* n),两个参数分别代表字符串的长度和模式串的长度,空间复杂度o(1),这里没有考虑存放匹配的索引列表。
    KMP算法是在此基础上的一种改进,它利用m维数组或其他线性结构存放了下一次匹配的模式位置,所以利用空间换取了一部分时间优化,但是具体时间复杂度会根据具体的字符串有较大的差别,但是性能如果最恶劣的话,也是o(m*n)。但是在很多时候,普通算法的执行时间并不比KMP慢多少,而且空间复杂度很低,所以现在依然被采用。

    这里先略去正则表达式里复杂的语法规则不管,用Python实现一个普通搜索算法,然后再写一个最简单的KMP算法。

    def pattern_match(str, pattern):  # 普通模式匹配算法,返回所有的索引
        index = []
        for _ in xrange(0, len(str)):
            i = _
            j = 0
            while j < len(pattern):
                if i < len(str) and str[i] == pattern[j]:
                    i += 1
                    j += 1
                else:
                    break
            if j == len(pattern):
                index.append(_)
        return index
    
    str = '90hnfuewdiohnfge'
    pattern = 'hnf'
    index = pattern_match(str, pattern)
    
    print index

    下面是 KMP算法,我自己写的:

    def kmp_pattern_match(str, pattern):
        index = []
        j = 0
        for i in xrange(0, len(str)):
            j = get_next(pattern, j)
            while j < len(pattern):
                if i < len(str) and str[i] == pattern[j]:
                    i += 1
                    j += 1
                else:
                    break
            if j == len(pattern):
                index.append(i-j)
                j = 0
        return index
    
    
    def get_next(pattern, index):  # index 范围为 1 到 len(pattern),算上 len(pattern)
        next_list = next_index(pattern)
        return next_list[index]
    
    
    def next_index(pattern):  # 返回一个列表,表示对应索引的下一跳索引
        next_list = [0, 0]
        for _ in xrange(2, len(pattern)):
            temp_list = [0]
            for i in xrange(1, _):
                if pattern[0:i] == pattern[_-i:_]:
                    temp_list.append(i)
            next_list.append(max(temp_list))
        return next_list

    在KMP上进一步扩展就是RE,正则表达式。但是记忆正则匹配是个麻烦的事情,前一段时间使用正则表达式处理文本比较多,所以很多字符的含义都记得,但是现在过了一段时间没有使用,很多的正则语法又忘记了。如果要自己实现一个正则表达式的话,我认为需要解决的几个问题是:栈队列存放模式,把模式和函数组合起来,模式匹配算法。

        原文作者:KMP算法
        原文地址: https://blog.csdn.net/dongrixinyu/article/details/78714366
        本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
    点赞