基于Python的数据结构实验——字符串的模式匹配(BF和KMP算法代码实现)(附详细代码和注释)

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(非索引)。
"""

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河之书Liu_Zixin

不要打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值