ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【数据结构 - 串 - KMP算法】next数组的推导【C语言】

2021-02-01 23:01:54  阅读:252  来源: 互联网

标签:子串 ... nextval next 数组 KMP C语言 个字符


KMP算法中,当主串字符s[i]不等于子串字符t[j]时,希望知道s[i]接下来与子串哪个字符比较


目录


1 假设

  • 主串S:‘s[1]s[2]…s[n]’
  • 子串T:‘t[1]t[2]…t[m]’
  • 一般地,n>=m

2 推导

  • 已有部分匹配结果:

    's[i-j+1]s[i-j+2]...s[i-1]' = 't[1]t[2]...t[j-1]'

  • 则必有

    's[i-k+1]s[i-k+2]...s[i-1]'='t[j-k+1]t[j-k+2]...t[j-1]'

  • 当s[i]不等于t[j]时,子串T需要向右移动,假设此时s[i]应该与t[k]继续比较,k<j

  • 则有新的部分匹配结果:

    's[i-k+1]s[i-k+2]...s[i-1]'='t[1]t[2]...t[k-1]'

    且不存在k’<k满足

    's[i-k'+1]s[i-k'+2]...s[i-1]'='t[1]t[2]...t[k'-1]'

  • 综合上述等式有:

    't[1]t[2]...t[k-1]' = 't[j-k+1]t[j-k+2]...t[j-1]'
    
  • next[j]=k表示:当子串第j个字符与主串第i个字符不相等时,应该用子串第k个字符接着与主串第i个字符比较

    • 需要向右移动j-k个字符距离
  • 则有next数组的定义

3 next数组的定义

next[j] =
	- 0		当j=1时
	- max{k | 1<k<j,且't[1]t[2]...t[k-1]'='t[j-k+1]t[j-k+2]...t[j-1]'}	当此集合不空时
	- 1		当其他情况时


在这里插入图片描述

4 解释

  • 1<=k<j
  • 1<=j<=m

  • j=1时,不存在k,使得k<j,因此,next[j]=0,表示没有字符
  • j>1时,
    • 若j=2,显然有k=1
    • 若j>2,则考虑部分匹配结果,取满足定义中等式的最大的k,可能的k值:j-1、j-2、…、1、0

    • 又k=0,表示找不到满足定义中等式的k,因此,next[j]=1,归入其他情况
    • 又k=1,表示子串第1个字符与主串第i个字符比较,意义特殊,单独列出,归入其他情况

  • 区分:作为字符位置的k、表示不存在的k(即k=0)

5 代码实现

说明:

  • 由next数组的定义,用递推的方法有:
  • 显然,next[1]=0
  • 设next[j]=k,则有:‘t[1]t[2]…t[k-1]’=‘t[j-k+1]t[j-k+2]…t[j-1]’
  • 对next[j+1],子串T对子串T进行模式匹配,
    • 若t[k]==t[j],则有:‘t[1]t[2]…t[k]’=‘t[j-k+1]t[j-k+2]…t[j]’,于是next[j+1]=k+1
    • 若t[k]不等于t[j],则考虑next[k]=k’,显然,1<k’<k<j
      • 若t[k’]==t[j],则next[j+1]=k’+1
      • 若t[k’]不等于t[j],则…,以此类推
    • 直到不存在k’来参与比较时,认为k’=0,从而有next[j+1]=0+1=1,表示子串第1个字符与主串第i个字符比较

代码:

//函数名:get_next
//功能:求next数组的值
Status get_next(SString T, int next[])
{
    int j = 1;
    int k = 0;
    
    //初值
    next[1] = 0;
    
	//j的范围:1<=j<=T[0]
    while (j < T[0])
    {
        //若k=0,表示找不到k,next[j+1]=1,因此,j和k都需要往下移一位
        //若T[j]==T[k],next[j+1]=k+1,因此,j和k都需要往下移一位
        if (k==0 || T[j]==T[k])
        {
            ++j;
            ++k;
            next[j] = k;
        }
        else
        {
            //若T[j]不等于T[k],则考虑next[k]=k' 
            k = next[k];
        }
    }
    
    return OK;
}

6 例子

  • 理论结果:
    next数组的推导 - 1
  • 运行结果:
    next数组的推导 - 2

7 补充

  • next数组仍可以改进:

    • 当子串T中出现【连续多个相同字符】时,若s[i]与t[j]不相等,而next[j]=k,t[j]==s[k],从而s[i]与t[k]没有必要再比较
    • 则有nextval数组
  • nextval数组

说明:

  • 由next数组的定义,用递推的方法有:
  • 显然,next[1]=0
  • 设next[j]=k,则有:‘t[1]t[2]…t[k-1]’=‘t[j-k+1]t[j-k+2]…t[j-1]’
  • 对next[j+1],子串T对子串T进行模式匹配,
    • 若t[k]==t[j],则有:‘t[1]t[2]…t[k]’=‘t[j-k+1]t[j-k+2]…t[j]’,于是next[j+1]=k+1
    • 若t[k]不等于t[j],则考虑next[k]=k’,显然,1<k’<k<j
      • 若t[k’]==t[j],则next[j+1]=k’+1
      • 若t[k’]不等于t[j],则…,以此类推
    • 直到不存在k’来参与比较时,认为k’=0,从而有next[j+1]=0+1=1,表示子串第1个字符与主串第i个字符比较
    • 当t[k]==t[j]时,nextval[j+1]=k+1
      • 对子串T,若t[j+1]
        ​ ==t[ nextval[j+1] ]
        ​ ==t[ nextval[ nextval[j+1] ] ]
        ​ ==…,以此类推
      • 找到最小的k’,使得t[j+1]不等于t[k’],从而nextval[j+1]=nextval[ nextval[j+1] ]=…=k’
      • 若找不到这样的k’,则令k’=0,从而nextval[j+1]=nextval[ nextval[j+1] ]=…=0,表示找不到
//函数名:get_nextval
//功能:求nextval数组的值
Status get_nextval(SString T, int nextval[])
{
    int j = 1;
    int k = 0;
    
    //初值
    nextval[1] = 0;
    
	//j的范围:1<=j<=T[0]
    while (j < T[0])
    {
		//若k=0,表示找不到k,next[j+1]=1,因此,j和k都需要往下移一位
        //若T[j]==T[k],next[j+1]=k+1,因此,j和k都需要往下移一位
        if (k==0 || T[j]==T[k])
        {
            ++j;
            ++k;
            
            if (T[j] != T[k])
            	nextval[j] = k;
            else
            	//因为从nextval[1]开始就一直取最小的k, 
				//	所以这里去找上一个k,即nextval[k],就是要找的k' 
            	nextval[j] = nextval[k];
        }
        else
        {
            //若T[j]不等于T[k],则考虑next[k]=k'
            k = nextval[k];
        }
    }
    
    return OK;
}

运行结果:
next数组的推导 - 3

  • 如果考试的时候,让求字符串“abcaabbabcabaacbacba”的next数组值和nextval数组值,怎么快速求出来?【结果如下】
    next数组的推导 - 4

8 参考文献

  • 严蔚敏, 吴伟民. 数据结构(C语言版)[M]. 北京: 清华大学出版社, 2007.

补充:
水平不高,可能还有做得不够好的地方,
希望能和大家交流学习,
转载请注明出处。

标签:子串,...,nextval,next,数组,KMP,C语言,个字符
来源: https://blog.csdn.net/COIaj4/article/details/113449274

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有