【串】字符串搜索算法

1. 简单模式匹配算法
想象一下,你手里有一本厚厚的书(主串S),你想找里面有没有一段特定的文字(模式串T)。简单模式匹配算法就像是你用手指从书的第一页开始,一行一行地和那段文字比对。
如果你手指指的那一行和那段文字的第一个字一样,你就继续往下看下一个字,如果还一样,就继续比对,直到所有的字都对上了,你就找到了这段文字。
如果中间有个字不一样,你就不看了,把手指挪到下一行重新开始比对。
如果你把整本书都翻完了,那段文字还是没有出现,那就是没找到。


1.1 简单模式匹配算法的算法原理
这个算法是字符串搜索的基础形式,其核心思想是顺序比较主串(S)模式串(T)的字符。如果当前字符不匹配,算法将主串的索引(i)回退到上一次匹配开始的位置(由变量k记录),然后继续比较。如果模式串的所有字符都匹配成功,返回匹配开始的位置;如果整个主串遍历完都没有匹配成功,则返回0。


代码逻辑:
定义两个指针 i 和 j ,分别指向主串和模式串的当前字符。
用 while 循环进行字符比较,如果字符相同,则两个指针都向前移动。
如果字符不匹配,则更新 i 为 k+1 , j 重置为1, k 更新为下一次比较的开始位置。
如果 j 超过了模式串的长度,表示匹配成功,返回 k 的值;否则,返回0。

串的结构体定义。
typedef struct{
char ch[MaxSize];//记录字符串的数组
int length;//记录串的实际长度
}SString;
串的简单模式匹配算法。
int Index(SString S,SString T){
int i=1,j=1,k=i;//变量 i,j 作为主串和子串的索引,k 记录此次比较的开始位置
while(i<=S.length&&j<=T.length){
if(S.ch[i]==T.ch[j]){//顺序比较主串和子串字符
i++;
j++;
}
else{//比较失败则重新回到下一次比较的开始位置
i=k+1;//更新 i 为下一次比较主串的开始位置
j=1;//更新 j 为下一次比较模式串的开始位置
k=i;//变量 k 记录下一次比较的开始位置
}
}
if(j>T.length)//模式匹配成功,返回 k
return k;
else//模式匹配失败,返回 0
return 0;
}


 


2. KMP算法
KMP算法就像是你更聪明地找那段文字。在开始之前,你先看看那段文字,找出里面有哪些字是重复的,或者哪些字后面跟着的字和前面的字一样,然后记下来。
这样,当你在书里找的时候,如果发现当前的字和那段文字不匹配,你就不用从头开始,而是根据你之前记下来的信息,知道应该从那段文字的哪个位置开始重新比对。
这样做的好处是,如果那段文字很长,你就不用每次都从头开始比对,可以节省很多时间。
简单来说,KMP算法通过一些预处理,让你在找文字的时候更加高效,不用每次都从头开始,而是可以根据情况跳过一些已经确定不会匹配的部分。
 

2. 1KMP算法的算法原理
KMP算法是一种改进的字符串搜索算法,它通过预处理模式串来创建一个部分匹配表( next 数组),这个表用于在字符不匹配时确定模式串应该回溯到哪个位置,而不是简单地将模式串的指针重置为1。


代码逻辑:
首先,通过 get_next 函数计算模式串的 next 数组。这个数组的每个元素 next[i] 表示在索引 i 处字符不匹配时,模式串应该回溯到哪个位置。
如果 j 为0或当前字符与前一个字符相同,则 i 和 j 都向前移动, next[i] 更新为 j 。
如果当前字符与前一个字符不同,则 j 回溯到 next[j] 。
然后,使用 KMP 函数进行模式匹配。
类似于简单模式匹配,使用 i 和 j 两个指针进行字符比较。
如果字符不匹配, j 回溯到 next[j] ,而不是重置为1。
如果 j 超过模式串的长度,表示匹配成功,返回匹配开始的索引位置;否则,返回0。
KMP算法的优势在于它避免了简单模式匹配中的回溯,提高了字符串搜索的效率。通过预处理模式串,KMP算法在最坏情况下的时间复杂度为O(n+m),其中n是主串长度,m是模式串长度。
 

串的 KMP 算法。
void get_next(SString T,int next[]){
int i=1,j=0;//变量 i 记录主串后缀结束位置,变量 j 记录模式串前缀结束位置
next[1]=0;//初始化第一个字符的 next 值
while(i<T.length){
if(j==0||T.ch[i]==T.ch[j]){//若遍历字符相同或回溯到头就更新 next 数组
i++;
j++;
next[i]=j;
}
else//若遍历字符不同,则回溯
j=next[j];
}
}
int KMP(SString S,SString T,int next[]){
int i=1,j=1;//变量 i,j 作为主串和子串的索引
while(i<=S.length&&j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){//顺序比较主串和子串字符
i++;
j++;
}
else//若不相等,则 j 回溯
j=next[j];
}
if(j>T.length)//模式匹配成功,返回子串所在位置
return i-T.length;
else//模式匹配失败,返回 0
return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值