(七)数据结构-串

一、串的定义和实现

字符串简称串,计算机在非数值处理的对象基本都是字符串数据

1.1串的定义

串(string)是由零个或多个字符组成的有序序列,一般记为S=‘a1a2a3…an’(n>=10)
其中S是串名,单括号括起来的字符序列是串的值;
ai可以是字母、数字或者其他字符
串中字符的个数n称为串的长度;
当n=0时的串称为空串;

1.2子串、主串

串中任意多个连续的字符组成的子序列称为该串的子串
包含子串的串称为主串

1.2.1串中的位置

注意:由一个或多个空格(空格是特殊字符)组成的串称为空格串
(注意:空格串不是空串)并且空格串的长度为串中空格字符的个数

  • 某个字符在串中的序号称为该字符在串中的位置
  • 子串在主串中的位置以子串的第一个字符在主串的位置来表示
    当两个串的长度相等对应位置的字符都相等的时候,称这两个串是相等的

串的模式匹配算法包括:朴素模式匹配算法(暴力匹配方法)、KMP算法

二、串的朴素模式匹配算法(暴力匹配方法)

子串的定位操作通常称为串的模式匹配,它是求子串(通常称为模式串)在主串中的位置。
算法思想:

  1. 主串长度n,模式串长度m
  2. 它是将主串中所有长度为m的子串与模式串对比
  3. 直到找到第一个与模式串完全匹配的子串,并返回子串起始位置,若所有的子串都不匹配,则返回0
    (最多对比n-m+1个子串)

在这里插入图片描述

若当前子串匹配失败,则主串指针i指向下一个子串的第一个位置i=i-j+2(主串指针回溯)
模式串指针j回到模式串的第一个位置
最坏时间复杂度为(nm)

三、KMP算法

KMP算法就是想要利用已经匹配的信息来提高搜索的效率,且为了不发生不必要的回溯

KMP的时间复杂度O(n+m)
求next数组的时间复杂度为O(m)
模式匹配过程最坏时间复杂度O(n)

在这里插入图片描述

根据图片为例,当用朴素匹配算法的时候,匹配到位置6的时候,主串和模式串的出现了不匹配的情况,但是位置1-5是对应的,(不匹配的字符之前,一定是和模式串一致的)为了不发生不必要的回溯,我们可以将朴素模式匹配算法进行改进,改进后的算法称为kmp算法

当匹配到第六个元素出现匹配失败的时候:

  1. 匹配到了j=6发现不匹配的时候,可以得知j=1~5时,主串和模式串一定是对应的,所以就没有必要用朴素匹配模式的时候

  2. 依次将指针往后挪i=2,j=1,发现不匹配
    在这里插入图片描述

  3. 再继续将指针往后挪i=3,j=1,发现i=3==j=1,但是i=4不等于j=2,发现不匹配

  4. 再继续将指针往后挪i=4,j=1,发现i=4j=1,i=5j=2,此时对i=6是否能够匹配未知,那么我们可以令主串指针i不变,模式串指针j=3
    在这里插入图片描述
    当匹配到第五个元素出现匹配失败的时候:

  5. 匹配到了j=5时不匹配的时候,可以得知j=1~4时,主串和模式串一定是对应的,所以就没有必要用朴素匹配模式的时候

  6. 依次将指针往后挪i=2,j=1,发现不匹配

  7. 再继续将指针往后挪i=3,j=1,发现i=3==j=1,但是i=4不等于j=2,发现不匹配

  8. 再继续将指针往后挪i=4,j=1,发现i=4==j=1,此时对i=5是否能够匹配未知,那么我们可以令主串指针i不变,模式串指针j=2

当匹配到第1个元素出现匹配失败的时候:

  1. 我们尝试匹配下一个相邻子串,那么在代码角度我们可以让j=0在这里插入图片描述
    那么此次改进的模式串指针如下:(并且这个改进的模式串只适用于该模式串’abaabc’)
    在这里插入图片描述
    那么我们可以用next数组将这个结果存起来,表明当我们在某个位置发生失配的时候,我们将j值修改为多少
    第一个位置比较特殊,不仅要把j修改为0,还需要将i++和j++
    (next数组的长度只与模式串相关,与主串无关)

在这里插入图片描述

三、KMP算法优化(nextval数组)

3.1nextval数组的由来

  • 假设模式串匹配到i=3出现匹配失败的时候,那么我们从next数组中我们可以将此时j=3挪到j=1,但是挪到j=1还是出现a,可以知道j=1和j=3都是匹配失败,所以我们完全可以让j=0,因为若j=1的话,我们可以知道是注定匹配失败的,所以最好的情况是直接让next3等于0

在这里插入图片描述

  • 假设模式串匹配到j=5的时候出现匹配失败,那么此时从next数组可以知道将j=5挪到j=2,虽然我们不知道此时i=5的字符是什么,但是我们可以确定的是肯定不是b,所以让j=2这个匹配操作肯定也是失败的,那么此时我们应该将j=1开始匹配
  • 所以与多了一步,我们不如修改next[5]的值=1
    在这里插入图片描述
    此时我们只优化了next数组,我们将进行优化得到nextval在这里插入图片描述

3.1手算nextval数组

我们首先算出next数组,再由next数组求nextval数组
nextval[0]=0:我们无脑写0
nextval[2]=0: 此时j=3的值是a,next[2]=1指向j=1,发现j=3的值与j=1的值相等,那么我们就将nextval[3]的值等于next[1]中的nextval的值

nextval[6]=4: 此时j=6的值是a,next[6]=4指向j=4,发现j=6的值与j=4的值不相等,那么我们就将nextval[6]的值等于自己的next[6]

在这里插入图片描述

3.1手算next数组

next数组的作用:当模式串的第j个字符失配的时,从模式串的第next[j]继续往后匹配
任何模式串都一样,第一个字符不匹配时,只能匹配下一个字符,因此以后的都写为next[1]=0

任何模式串都一样,第一个字符不匹配时,只能匹配下一个字符,因此以后的都写为next[2]=1

next[4]的含义:当模式串在第4个字符出现匹配失败
步骤:
接着我们可以知道前三个字符是匹配成功的
那么我们在第四个字符前面划一条分界线
接着我们让模式串一步步往右边移动

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

一直往右移动的时候,都无法匹配,直到移动到整个模式串跨越了整个分界线
接下来我们应该对比的是i和j(模式串的第一个字符)所指的元素,所以当模式串第四个字符匹配失败的时候,我们就让j的指针直接指向j=1

next[5]:我们首先让模式串一步一步往右移动,无法匹配接着一直移动,此时匹配上了,那么我们可以让j=2
在这里插入图片描述
例子:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值