串的模式匹配算法

1.模式匹配算法概览

1.1算法目的:

确定主串中所含模式串第一次出现的位置(即定位操作

1.2算法种类

  • BF算法(Brute-Force,又称古典的、经典的、朴素的、穷举的)
  • KMP算法(特点:速度快)

1.3子串与模式串的区别

子串:主串的一部分,一定存在
模式串:不一定能在主串中找到

2.BF------简单匹配算法(实际上就是暴力查找)

int BFindex(sstring s, sstring t)//可以从主串的第一个位置开始匹配
int BFindex(sstring s, sstring t,int pos)//也可以从主串的第任意位置开始匹配

第二种方法只需要将i初始化为传入的pos即可(i:主串的第一个匹配位置),其余部分与第一种方法完全一致,本篇中不再过多赘述

2.1算法的核心思路与核心步骤:

2.1.1核心思路:设主串长度为n模式串长度为m

将主串中所有长度为m的子串(最多为n-m+1个子串)依次与模式串对比,直到找到完全匹配的子串所有的子串都不匹配为止。

2.1.2 核心步骤

  • <1>字符匹配失败时,重置匹配位置并重新开始比较
    注意主串重置的位置为当前匹配起始位置的下一个位置
    公式为:i-j+2
    实例图解
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
按照这种滑动匹配的方式,一直到匹配成功

  • <2>匹配成功时,返回主串中模式串的首个字符下标
    公式为:i-t.length
    比如上述图解中,匹配成功时,j=7,i=10,返回i-t.length=10-6=4
    如下图:在这里插入图片描述

2.2时间复杂度分析:O(nm)

最坏的情况,每个子串都要对比 m 个字符,共 n-m+1个子串
复杂度=0((n-m+1)m)=0(nm)
注:很多时候,n远远大于m

2.3算法步骤:

(1)初始化匹配位置(注意是否是从下标1开始存起)
(2)逐字符比较主串和模式串中的字符
终止条件:i <= s.length && j <= t.length
<1> 若当前字符匹配成功,则比较下一个字符
<2> 若当前字符匹配失败,重置匹配位置并重新开始比较
公式:i=i-j+2
(3)判断匹配结果
<1>匹配成功返回主串中模式串的首个字符位置
判断条件:j>t.length
公式:i-t.length
<2>匹配失败,返回 0

#include<stdio.h>
#include<stdlib.h>

#define bool int
#define true 1
#define false 0

#define  MAXSIZE 255//预定义最大串长为255

//1.串类型定义(静态数组)
typedef struct
{
	char ch[MAXSIZE + 1];//每个空间存储一个字符
	//这里加1的目的是,串的有效元素要从下标1开始存起,方便管理,长度最大仍然为255
	int length;//串的实际长度
}sstring;
//sstring:结构体别名,用来定义串



// 串的简单匹配算法——BF (Brute Force)
// 传入主串 s 和模式串 t,返回匹配成功的第一个位置,未匹配返回 0
int BFindex(sstring s, sstring t)
{
    // [1] 初始化匹配位置
    // i 初始化为主串的第一个字符位置,j 初始化为模式串的第一个字符位置
    int i = 1, j = 1;

    // [2] 逐字符比较主串和模式串中的字符
    while (i <= s.length && j <= t.length)
        // 当 i > s.length 时,表示主串已比较完毕
        // 当 j > t.length 时,表示模式串已比较完毕
        // 此处用 <= 是因为下标从 1 开始,确保不会越界
    {
        // <1> 若当前字符匹配成功,则比较下一个字符
        if (s.ch[i] == t.ch[j])
        {
            i++; // i 移动到主串的下一个字符
            j++; // j 移动到模式串的下一个字符
        }
        // <2> 若当前字符匹配失败,重置匹配位置并重新开始比较
        else
        {
            // <核心1> 主串的匹配位置重置为当前匹配起始位置的下一个位置
            i = i - j + 2;
            // 模式串的匹配位置重置为第一个字符
            j = 1;
        }
    }

    // [3] 判断匹配结果
    if (j > t.length)
        // 匹配成功,返回主串中模式串的首个字符位置
        // j > t.length 表示模式串已经完全匹配,j 此时等于 t.length + 1
    {
        //<核心2>返回主串中模式串的首个字符位置
        return i - t.length;
        
    }
    else
    {
        // 匹配失败,返回 0
        return 0;
    }
}
int main()
{
    // 初始化主串和模式串
    sstring s1 = { "#abcdef", 6 };  // 主串: "abcdef",长度为6
    sstring t1 = { "#cde", 3 };     // 模式串: "cde",长度为3

    sstring s2 = { "#aaaaaab", 7 }; // 主串: "aaaaaab",长度为7
    sstring t2 = { "#aab", 3 };     // 模式串: "aab",长度为3

    sstring s3 = { "#abcd", 4 };    // 主串: "abcd",长度为4
    sstring t3 = { "#efg", 3 };     // 模式串: "efg",长度为3

    sstring s4 = { "#aaaaa", 5 };   // 主串: "aaaaa",长度为5
    sstring t4 = { "#aaaaaa", 6 };  // 模式串: "aaaaaa",长度为6

    sstring s5 = { "#abcabcabc", 9 }; // 主串: "abcabcabc",长度为9
    sstring t5 = { "#abc", 3 };       // 模式串: "abc",长度为3

    // 执行测试用例
    printf("测试用例 1: 预期 3, 结果 %d\n", BFindex(s1, t1));
    printf("测试用例 2: 预期 5, 结果 %d\n", BFindex(s2, t2));
    printf("测试用例 3: 预期 0, 结果 %d\n", BFindex(s3, t3));
    printf("测试用例 4: 预期 0, 结果 %d\n", BFindex(s4, t4));
    printf("测试用例 5: 预期 1, 结果 %d\n", BFindex(s5, t5));
    return 0;
}

在这里插入图片描述

2.4补录:当有效字符从下标为零处开始存储时

1.算法步骤的差异:

(1)初始化匹配位置(注意是从下标0开始存起)
(2)逐字符比较主串和模式串中的字符
终止条件:i < s.length && j < t.length
<1> 若当前字符匹配成功,则比较下一个字符
<2> 若当前字符匹配失败,重置匹配位置并重新开始比较
公式:i=i-j+1
(3)判断匹配结果
<1>匹配成功返回主串中模式串的首个字符位置
判断条件:j>t.length-1
公式:i-t.length(此条件不变)
<2>匹配失败,返回 0

除了返回位序时的操作不变外,其余操作都需要调整
图解如下
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>

#define bool int
#define true 1
#define false 0

#define  MAXSIZE 255//预定义最大串长为255

//1.串类型定义(静态数组)
typedef struct
{
    char ch[MAXSIZE];//每个空间存储一个字符
    int length;//串的实际长度
}sstring;
//sstring:结构体别名,用来定义串



// 串的简单匹配算法——BF (Brute Force)(下标为0开始存)
// 传入主串 s 和模式串 t,返回匹配成功的第一个位置,未匹配返回 0
int BFindex(sstring s, sstring t)
{
    // [1] 初始化匹配位置
    // i 初始化为主串的第一个字符位置,j 初始化为模式串的第一个字符位置
    int i = 0, j = 0;

    // [2] 逐字符比较主串和模式串中的字符
    while (i < s.length && j < t.length)
        // 当 i == s.length 时,表示主串已比较完毕
        // 当 j == t.length 时,表示模式串已比较完毕
        // 此处用 < 是因为下标从 0 开始,确保不会越界
    {
        // <1> 若当前字符匹配成功,则比较下一个字符
        if (s.ch[i] == t.ch[j])
        {
            i++; // i 移动到主串的下一个字符
            j++; // j 移动到模式串的下一个字符
        }
        // <2> 若当前字符匹配失败,重置匹配位置并重新开始比较
        else
        {
            // <核心1> 主串的匹配位置重置为当前匹配起始位置的下一个位置
            i = i - j + 1;
            // 模式串的匹配位置重置为第一个字符
            j = 0;
        }
    }

    // [3] 判断匹配结果
    if (j > t.length-1)
        // 匹配成功,返回主串中模式串的首个字符位置
        // j == t.length 表示模式串已经完全匹配
    {
        //<核心2>返回主串中模式串的首个字符位置
        return i - t.length;//此操作与下标为1开始存操作一致

    }
    else
    {
        // 匹配失败,返回 -1(因为0此时为有效下标)
        return -1;
    }
}
int main()
{
    // 初始化主串和模式串
    sstring s1 = { "abcdef", 6 };  // 主串: "abcdef",长度为6
    sstring t1 = { "cde", 3 };     // 模式串: "cde",长度为3

    sstring s2 = { "aaaaaab", 7 }; // 主串: "aaaaaab",长度为7
    sstring t2 = { "aab", 3 };     // 模式串: "aab",长度为3

    sstring s3 = { "abcd", 4 };    // 主串: "abcd",长度为4
    sstring t3 = { "efg", 3 };     // 模式串: "efg",长度为3

    sstring s4 = { "aaaaa", 5 };   // 主串: "aaaaa",长度为5
    sstring t4 = { "aaaaaa", 6 };  // 模式串: "aaaaaa",长度为6

    sstring s5 = { "abcabcabc", 9 }; // 主串: "abcabcabc",长度为9
    sstring t5 = { "abc", 3 };       // 模式串: "abc",长度为3

    // 执行测试用例
    printf("测试用例 1: 预期 2, 结果 %d\n", BFindex(s1, t1));
    printf("测试用例 2: 预期 4, 结果 %d\n", BFindex(s2, t2));
    printf("测试用例 3: 预期 -1, 结果 %d\n", BFindex(s3, t3));
    printf("测试用例 4: 预期 -1, 结果 %d\n", BFindex(s4, t4));
    printf("测试用例 5: 预期 0, 结果 %d\n", BFindex(s5, t5));
    return 0;
}

在这里插入图片描述

3.KMP------(旧版看猫片算法,O(∩_∩)O)

暂时没学会,等以后学会了再更新

  • 28
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值