自编代码展示:
'''
KMP算法的Python实现:
若next[j] = i;表示如下含义:
在模式字符串pattern中,取其子串subString = pattern[0:j+1]
该子串的最大前缀和最大后缀相同,长度为i+1;
即subString[0:i+1] == subString[-i-1:];
并且满足: i<j; 否则当i==j时表示subString[:]==subString[:]无意义
'''
# getNext函数接收一个字符串,返回一个列表,表示next数组
def getNext(pattern):
length = len(pattern)
assert length > 0
next = [None] * length
for pointer in range(length):
if pointer == 0: # 第一个位置取值恒为-1
next[pointer] = -1
continue
else:
if pattern[pointer] == pattern[next[pointer-1]+1]: # 利用前一个位置的前后缀匹配关系判断下一个字符是否继续得到匹配
next[pointer] = next[pointer-1] + 1 # 下一个字符仍然匹配,因此长度加1
else:
if next[pointer-1] == -1: # 表示截止到前一个字符,没有前后缀匹配,而且从上一个if语句得知当前字符也未匹配
next[pointer] = -1 # 未得到匹配,取值为-1
continue # 继续下一次循环,计算next数组的下一个取值
scan = next[next[pointer-1]] # 当前匹配失败后,考虑前一个位置的前后缀匹配关系
while(True):
if pattern[scan+1] == pattern[pointer]: # 得到匹配
next[pointer] = scan + 1 # 找到匹配的前后缀
break # 跳出while循环
else:
if scan == -1: # 表示整个字符串中都未得到匹配,因此取值为-1
next[pointer] = -1 # -1表示未得到匹配
break
else:
scan = next[scan] # 匹配失败,继续前溯
return next # 返回next数组
# KMP函数接收一个文本字符串text和一个模式字符串pattern,实现KMP算法
def KMP(text,pattern): # 返回在文本字符串text中匹配子串的起始位置,若不匹配则返回None
next = getNext(pattern) # 获取next数组,列表类型
length_txt = len(text) # 获得文本字符串的长度
length_pat = len(pattern) # 获得模式字符串的长度
ptr_txt, ptr_pat = 0, 0 # 初始化两个字符串的指针位置,或者理解为索引位置
while(ptr_txt<length_txt and ptr_pat<length_pat): # 循环遍历整个文本字符串
if pattern[ptr_pat] == text[ptr_txt]: # 字符获得匹配
ptr_txt += 1 # 文本字符串的指针加1
ptr_pat += 1 # 模式字符串的指针加1
if ptr_pat == length_pat: # 判断是否对模式字符串遍历完成
return (ptr_txt - ptr_pat) # 获得匹配,返回匹配的起始位置
continue # 当前字符串成功匹配,继续进行下一次比较
else:
if ptr_pat == 0: # 模式字符串前溯到起始位置,仍旧未获得匹配的前缀后缀,因此将文本字符串指针向后移动
ptr_txt += 1 # 文本字符串的指正位置向后移动,继续扫描两个字符串进行比较
else:
ptr_pat = next[ptr_pat-1] + 1 # 匹配失败之后前溯
return None # 整个文本字符串中都未出现模式字符串,匹配失败,返回未匹配的标志None
# pattern = 'abcabcacab'
# pattern = 'abaabcac'
# print('字符串:', pattern)
# print('next数组:', getNext(pattern))
text = input("请输入文本字符串:\t")
pattern = input("请输入模式字符串:\t")
print('您输入的模式字符串是:\t',pattern)
print("获取next数组:",getNext(pattern))
print('您输入的文本字符串是:\t',text)
position = KMP(text,pattern)
print("KMP函数返回结果为:\t",position)
if position == None:
print("文本字符串\n\t"+text+"\n中未出现模式字符串\n\t"+pattern)
else:
print("文本字符串\n\t"+text+"\n中出现模式字符串\n\t"+pattern+'\n的位置是:',position)
# text = 'acabaabaabcacaabc'
# pattern = 'abaabcac'
运行结果:
Microsoft Windows [版本 10.0.19044.2075]
(c) Microsoft Corporation。保留所有权利。
C:\Users\chenxuqi>cd /d F:\KMP算法
F:\KMP算法>python testKMP.py
请输入文本字符串: acabaabaabcacaabc
请输入模式字符串: abaabcac
您输入的模式字符串是: abaabcac
获取next数组: [-1, -1, 0, 0, 1, -1, 0, -1]
您输入的文本字符串是: acabaabaabcacaabc
KMP函数返回结果为: 5
文本字符串
acabaabaabcacaabc
中出现模式字符串
abaabcac
的位置是: 5
F:\KMP算法>
F:\KMP算法>
控制台下运行结果图:
# 本代码使用python语言,实现了KMP字符串匹配算法
NotFound = None
def get_next(pattern):
i,j = 0,0
pat_len = len(pattern)
next = [-1 for k in range(pat_len)]
for j in range(1,pat_len):
i = next[j-1]
while( (i>=0) and (pattern[i+1]!=pattern[j]) ):
i = next[i]
if (pattern[i+1]==pattern[j]):
next[j] = i+1
else:
next[j] = -1
return next
def KMP(string, pattern):
str_len,pat_len = len(string),len(pattern)
if str_len<pat_len:
return NotFound
next = get_next(pattern)
ptr_str,ptr_pat = 0,0
while(ptr_str<str_len and ptr_pat<pat_len):
if(string[ptr_str]==pattern[ptr_pat]):
ptr_str += 1
ptr_pat += 1
elif (ptr_pat>0):
ptr_pat = next[ptr_pat-1] + 1
else:
ptr_str += 1
return (ptr_str-ptr_pat if ptr_pat==pat_len else NotFound )
if __name__=='__main__':
string = input('请输入文本字符串:')
pattern = input("请输入模式字符串:")
position = KMP(string, pattern)
if position == NotFound:
print('Not Found.\n')
else:
print("所在位置为:", position)