1. 程式人生 > >python資料結構之KMP演算法的實現

python資料結構之KMP演算法的實現

我相信網上已經有很多關於KMP演算法的講解,大致都是關於部分匹配表的實現思路和作用,還有就是目標串的下標不變,僅改變模式串的下標來進行匹配,確實用KMP演算法,當目標串很大模式串很小時,其效率很高的,但都是相對而言。至於對於部分匹配表的作用以及實現思路,建議看一下這篇文章寫的是比較易懂的,英文看不懂?那你就看別的國人寫的吧,其實大概都差不多,我這裡主要是用python語言實現一個部分匹配表以及實現KMP演算法
首先是對於部分匹配表的實現,它的實現其實有兩種,一種是對目標串的所有子串的部分匹配值都計算出來放在一個數組裡面,想使用的時候之間通過下標取用就可以了,但我使用的是另外一種,實時計運算元字串的部分匹配值,也就是說,定義一個函式,當傳進一個字串時就返回一個其部分匹配值。其實這個函式就是一個核心,如果搞懂了這個函式,你想計算出全部的部分匹配值不是很簡單嗎?話不多說,我們貼出來程式碼:

# 函式用於求一個匹配子串的部分匹配值
def partialMatchTable(string):
    length = len(string)
    # 已經匹配的模式串的長度
    x = 1 # 用於表示字首字尾的長度,始終小於串長度
    stringMatchValues = []
    # 用於存放模式串的可能匹配值
    while x < length:
        if string[:x] == string[-x:]:
            # 如果字首和字尾相等,那麼,這就是一個可能的部分匹配值
            stringMatchValues.append(len(string[:x]))
            x += 1
        x += 1
    if not stringMatchValues:
        return 0
    # 如果沒有部分匹配值,則返回0
    return max(stringMatchValues)


以上函式比較簡單,就是比較而已,關鍵在於切片的獲取。這樣,你穿進去一個string,函式就返回一個它的部分匹配值。

重點在於KMP演算法的實現,實現程式碼如下:

import time
from 部分匹配表 import *

starTime = time.time()
def KMP_algorithm(t, p):
    lens = 0 # lens是已經匹配的串的長度
    tIndex, pIndex = 0, 0
    # 目標串和模式串的下標
    m, n = len(p), len(t)
    # m, n是模式串和目標串的長度
    while pIndex < m and len(t[tIndex:]) >= m-1:
        # 只有當p的下標小於m,而且t的剩餘的長度大於或者等於p的長度
        if p[pIndex] == t[tIndex]:
            pIndex +=1
            tIndex += 1
            # 如果兩個的相應下標的值相等,那麼接著比較下一個
        else:
        # 如果不相等
            string = p[:pIndex]
            # 這裡取出已匹配模式串
            if string == '':
            # 沒有已經匹配的模式串
                tIndex += 1
                pIndex = 0
            else:
            # 如果有已經匹配的模式串,我們知道目標字串的下標是不變的,改變的只有
            # 模式字串的下標
                pIndex = partialMatchTable(string)
    if pIndex == m:
        return (tIndex - m)
    print(len(t[tIndex:]))
    return ("不匹配")

t = open("目標串.txt", "r")
# 去掉字串之間的空格
for i in t.readlines():
    print(i.rstrip(), sep="", end="", file=open("目標串2.txt", "a"))
T = open("目標串2.txt", "r").read()

y = KMP_algorithm(T, "18117601")
print(y)
endTime = time.time()
print(starTime-endTime, end="執行時間")


程式碼中各個變量表示什麼已經講的很清楚了,其中一段對於檔案的操作,是去除檔案中的所有空格。

程式碼中的註釋已經講所有可能有困惑的地方都講清楚了,看的時候最後結合你圖看,上面連結裡面就有可能需要的圖解。嗯

差不多就是這樣,KMP演算法我可是研究了很長的時間才寫出來的。接下來我來講一下原理。
首先什麼是回溯?:
哈哈哈,就是目標串和模式串已經比較過的部分,如果在下一次比較中再進行比較那麼就是叫回溯,而KMP演算法成功的避免了回溯,至於怎麼避免的,我來用草稿紙畫一張圖,客官們湊合著看。
在這裡插入圖片描述

其實圖片已經能說明所有問題了! 就這樣,完, 不對,還有一種字串匹配演算法–Boyer-Moore演算法,它的效率可能比KMP演算法還要高很多,嗯,有興趣的可以關注一下,因為下一篇我想講講這個演算法。