1、创建名为 prac05_01.py 的文件,在其中编写包含顺序串的某些基本操作及 BF 算 法的类,具体步骤如下。
(1)创建主串 S 和模式串 T。
(2)在主串 S 中设置 BF 算法匹配的起始位置,并实现 BF 算法。
(3)主串 S 调用 BF 算法并以起始位置和模式串 T 为参数,验证 BF 算法的正确性。
3、创建名为 prac05_02.py 的文件,在其中编写 KMP 算法,同时需实现模式串的 ListNextValue 函数(即修正后的),具体步骤如下。
(1)在主串 S 中设置 KMP 算法匹配的起始位置,并实现 ListNextValue 函数。
(2)调用 ListNextValue 函数,求解模式串 T 的 ListNextValue 函数值。
(3)主串 S 调用 KMP 算法并以起始位置、模式串 T 及模式串 T 的 ListNextValue 函 数值为参数,验证 KMP 算法的正确性。
(我没有搞成两个文件,而是直接用的继承,反正python的继承比较简单)
(别问我为啥我说这个好理解,因为我看不懂书上给的代码,因此自己按照书上的原理硬写了一个,因此是严格按照书上原理来的,可能会好理解一点)
class StringList:
def __init__(self):
self.maxsize = 128 # 设置串的最大限值
self.string = [None] * self.maxsize # 预先构建一个空串
self.size = 0 # 串的实时长度
def Length(self): # 串长度获取
return self.size
def Add(self, str_1): # 写入串
for i, item in enumerate(str_1): # 使用enumerate()遍历输入的字符串,获取其位置i和所在位置的字符item
if self.size < self.maxsize: # 如果串未满
self.string[i] = item # 向串中写入数据
self.size += 1 # 实时长度增加
else:
print("串已满,无法写入。") # 判定串满不再写入
break # 终止循环
print("数据写入完毕。") # 数据写入提示
def SelectAll(self):
if self.size == 0: # 如果串为空
print("串为空。")
else:
for i, item in enumerate(self.string): # 遍历,原理同上
if item is not None: # 检查是否到达串的结尾,如果未达到
print(item, end="") # 打印串
else:
break # 到结尾了就中断
print("") # 换行用的
class BF(StringList): # BF算法的程序实现,继承StringList
def __init__(self):
super().__init__() # 继承StringList里的变量
def BF_Algorithm(self, pattern): # BF算法
if self.string[0] is None: # 判断主串是否为空(也可以用之前的self.length())
print("主串不能为空。")
elif pattern == "": # 判断模式串是否为空
print("模式串不能为空。")
elif len(pattern) > self.Length(): # 判断模式串是否大于主串(这个自然是不能大于的)
print("模式串长度不能小于主串。")
else: # 如果以上条件均正常,开始尝试匹配
judgement = True # 用来控制输出的,后面用到的时候会解释
for i in range(0, self.Length() - len(pattern) + 1): # self.Length() - len(pattern) + 1限定循环次数,意味着剩余的主串位数小于模式串时就已经停止循环了
if i != self.Length() - len(pattern): # 如果主串索引i没有到最后一次匹配开始的位置
for j in range(0, len(pattern)): # 启动模式串索引进行匹配
if j != len(pattern) - 1: # 如果没有轮到模式串的最后一个字符匹配
if pattern[j] == self.string[j + i]: # 如果模式串上的字符和主串上的对应字符相等
continue # 继续循环匹配下一个字符
else:
break # 反之直接终止循环,进入下一次移动主串索引开始新一轮匹配
else: # 如果轮到模式串的最后一个字符匹配
if pattern[j] == self.string[j + i]: # 如果匹配就显示匹配成功了,如果没有的话什么也不要做,直接进入下一次新的匹配循环
print("匹配成功,匹配的位置为%d(非索引)。" % (i + 1)) # 判定匹配成功
judgement = False # 将之前那个控制用的逻辑值修改
break # 终止(内层)循环
else: # 如果主串索引i到最后一次匹配开始的位置(开始最后一次整体匹配)
for j in range(0, len(pattern)): # 和上面的逻辑基本一致
if j != len(pattern) - 1:
if pattern[j] == self.string[j + i]:
continue
else:
if judgement: # 此处应用了之前的judgement,因为前面匹配成功后,外层循环不会终止,故仍然会循环最后一次检测,此处可以使用judgement作为标签防止输出多余信息
print("匹配失败。") # 此处不一样了,因为这已经是最后一次进行整体匹配了,因此一旦其中出现不匹配的直接判定匹配失败
break
else: # 如果judgement显示为False,说明之前匹配成功过,就不需要继续搞了,直接终止就行
break
else:
if pattern[j] == self.string[j + i]: # 这些和之前的也都一样,但是此处不需要再设置judgement标签了
print("匹配成功,匹配的位置为%d(非索引)。" % (i + 1))
else:
print("匹配失败。")
class KMP(StringList): # BF算法的程序实现,继承StringList
def __init__(self):
super().__init__() # 继承StringList里的变量
def NextList(self, pattern): # 想搞KMP,先搞KMP的核心之nextlist
nextlist = [None] * len(pattern) # 设置一个长度为pattern的空列表
for i in range(0, len(pattern)): # 循环pattern每个字符的位置
if i == 0: # 如果是第一个字符,nextlist设定该位置的迁移量是-1
nextlist[i] = -1
else:
counter = 0 # 计数器,也就是迁移量
for j in range(i - 1, 0, -1): # 外层循环到i时,此时i以前的几位字符可能存在1位到i-1位的数据相等
list_cache_1 = [] # 设置两个列表,分别用于存储0到j的数据和i-j到i的数据,便于后期判断
list_cache_2 = []
for k in range(j, 0, -1):
list_cache_1.append(pattern[j - k]) # 循环添加入数据
list_cache_2.append(pattern[i - k])
if list_cache_1 == list_cache_2: # 如果两表相等
counter += j # 表明在当前j下,存在最大的相同串,其长度为j
break
else:
continue
nextlist[i] = counter # 将nextlist相应位置赋值
print("模式串的NextList为:", nextlist)
return nextlist # 返回nextlist
def KMP_Algorithm(self, pattern): # KMP算法
if self.string[0] is None: # 判断同BF算法函数处
print("主串不能为空。")
elif pattern == "":
print("模式串不能为空。")
elif len(pattern) > self.Length():
print("模式串长度不能小于主串。")
else:
nextlist=self.NextList(pattern) # 获取之前历经千辛万苦得到的nextlist
j = 0 # 这是模式串使用的索引
judgement = True # 这个用处……跟前面的那个其实很相似
for i in range(self.Length()): # 这是主串使用的索引
if(self.string[i] == pattern[j]): # 如果经检查字符匹配
if(j == len(pattern) - 1): # 检查是否到了模式串的最后一个
print("匹配成功,匹配的位置为%d(非索引)。" % (i - j + 1)) # 如果是的话则匹配成功
judgement = False # 吧之前那个值赋为False
break # 终止循环
else: # 如果没有到最后一个
j += 1 # 那j+1进入下一次循环,此时相当于i和j都+1了
else: # 如果匹配失败,那就根据nextlist修改j的值进行下一次匹配
j = nextlist[j] + 1
if judgement:
print("匹配失败。")
b = KMP()
b.Add("aaaaaaa")
b.KMP_Algorithm("aaaaa")
a = BF()
a.Add("abcabcs")
a.BF_Algorithm("abc")
"""
简单测试一下,运行结果如下:
数据写入完毕。
模式串的NextList为: [-1, 0, 1, 2, 3]
匹配成功,匹配的位置为1(非索引)。
数据写入完毕。
匹配成功,匹配的位置为1(非索引)。
匹配成功,匹配的位置为4(非索引)。
"""