串(字符串)

本文介绍了字符串的定义和常见术语,详细阐述了顺序存储结构和链式存储结构在字符串操作中的应用,并重点讲解了两种模式匹配算法:BF算法和KMP算法。BF算法是一种简单的暴力匹配,时间复杂度为O(n*m),而KMP算法通过预处理优化,将时间复杂度降低到O(n+m)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、定义及常见术语

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
串相等:当两个串的长度相等且对应位置上的字符都相同时,这两个串才是相等的

所有的空串都是相等的

二、两种存储结构

2.1顺序存储结构(更常用)

#define MAXLEN 255
typedef struct {
    char ch[MAXLEN+1];//存储串的一维数组
    int length;//串的当前长度长度
} SString;

2.2 链式存储结构

#define CHUNKSIZE 80
typedef struct Chunk{
	char ch[CHUNKSIZE + 1];
	struct Chunk *next;
}Chunk;//串的结点类型

typedef struct {
	Chunk *head, *tail;//串的头、尾指针 
	int length;//串的当前长度 
}LString;//串的块链结构 

三、模式匹配算法

目的:确定主串中所含字串 (模式串) 第一次出现的位置

应用:搜索引擎、拼写检查、语言翻译、数据压缩

3.1 BF算法 (Brute-Force)

将主串的第pos个字符和模式串的第一个字符比较
若相等,继续逐个比较后续字符
若不等,从主串的下一字符开始,重新和模式串的第一个字符比较

int Index_BF(SString S, SString T, int pos) {
    int i = pos, j = 1;//为了方便描述,这里的sstring类的第零位置不储存元素
    while (i <= S.length && j <= T.length) {
    //若第一个不符合,则匹配失败;若第二个不符合,则匹配成功
        if (s.ch[i] == T.ch[j]) ++i, ++j;//主串和字串依次匹配下一个字符
        else {i = i-j+2; j = 1;} //回溯
        //i=i-j+2,理解为i-(j-1)+1。j从1到j走了j-1步,则i也走了j-1步。减j-1后再+1,是回到主串原来开始匹配的下一个位置
    }
    if (j > T.length) return i-T.length;
    else return 0; //模式匹配不成功
}
//主串长n,子串长m,时间复杂度O(n*m),复杂度较高。
 

在这里插入图片描述

3.2 KMP算法

可参考:KMP算法易懂版

补充:包含首字母,不包含尾字母的所有子串都称为前缀,包含尾字母,不包含首字母的所有子串都称为后缀
找最长的(长度小于比较指针左端子串长度的)公共前后缀
不需要看主串,只需要将模式串的相关信息提取出来之后就可以与任意的主串进行匹配。
公共前后缀的长度需小于比较指针左侧子串的长度
移动后,比较指针左侧子串的长度即为公共前后缀的长度
模式串的“最大公共前后缀长度+1”号位与主串当前位进行比较即可。

示例:
在这里插入图片描述

int Index_KMP(SString S, SString T, int pos) {
    int i = pos, j=1;
    while (i < S.length && j<=T.length) {
        if (j == 0 && S.ch[i] == T.ch[j]) ++i, ++j;
 //j == 0是因为当j退到0时,也就是主串的第i个字符与模式串的第一个字符不等时,应从主串的第i+1个字符重新与模式串的第一个字符作比较
        else j = next[j]; 
        //i不变,j后退,这里利用了一个next数组来存放j要飞到的位置,而不是每一次都从头开始
    }
    if (j > T.length) return i-T.length;//返回第一个字符的下标,匹配成功
    else return 0; //模式匹配不成功
}
 
void get_next(SString T, int &next[]) {//获得next数组,记录j的坐标位置
    i = 1; next[1] = 0; j = 0; 
	while (i < T.length) {
        if (j == 0 || T.ch[i] == T.ch[j]) {
            ++i; ++j;
            next[i] = j;
        }
        else j = next[j];
    } 
} 
//具体来说就是,j回溯改成,让模式串中模式匹配不成功位置之前的串中的最长前后缀的前缀到后缀位置,这样就推动了j的后移
//下图是示意图,其中next记录的是j可以飞到的位置,也就是最长公共前后缀的长度+1,注意最长前后缀的长度要小于不同位置之前串的长度才行!

可以提速到 O ( n + m ) O(n+m) O(n+m)
利用已经部分匹配的结果而加速模式串的滑动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值