C语言——数据结构——计算next和nextval

计算 “next” 和 “nextval” 是在串中进行模式匹配时经常使用的概念,通常用于字符串匹配算法中的 KMP(Knuth-Morris-Pratt)算法。

在 KMP 算法中,我们需要预先计算出一个称为 “next” 数组的辅助数组,它记录了模式串中每个位置的最长公共前后缀的长度。而 “nextval” 数组是在 “next” 的基础上进行了优化。

具体来说,给定一个长度为 m 的模式串,我们可以通过遍历模式串的每个位置来计算 “next” 数组。下面是计算 “next” 数组的步骤:

  1. 初始化一个长度为 m 的数组 next,next[0] = -1,表示第一个字符没有最长公共前后缀。

  2. 遍历 i 从 1 到 m-1,对于每个位置 i:

    • 令 j = next[i-1],表示 i-1 位置的最长公共前后缀的长度。
    • 不断向前回溯,直到 j >= 0 或者模式串的第 j+1 个字符与模式串的第 i 个字符相等为止。记为条件 j >= 0 && pattern[j+1] != pattern[i]。
    • 如果满足上述条件,则令 j = next[j],继续回溯,直到找到一个 j 使得 pattern[j+1] == pattern[i],或者回溯结束(j < 0)。
    • 更新 next[i] = j+1。

通过以上步骤,我们可以计算得到 “next” 数组。而 “nextval” 数组则是在 “next” 数组的基础上进行了优化,减少了回溯操作的次数。

在计算 “nextval” 数组时,我们需要进一步优化回溯的过程。具体步骤如下:

  1. 初始化一个长度为 m 的数组 nextval,其中 nextval[0] = -1,表示第一个字符没有最长公共前后缀。

  2. 遍历 i 从 1 到 m-1,对于每个位置 i:

    • 令 j = nextval[i-1],表示 i-1 位置的最长公共前后缀的长度。
    • 不断向前回溯,直到 j >= 0 或者模式串的第 j+1 个字符与模式串的第 i 个字符相等为止。
    • 如果满足上述条件,则记为条件 j >= 0 && pattern[j+1] != pattern[i]。
    • 如果满足条件 j >= 0 && pattern[j+1] != pattern[i],则令 j = next[j],继续回溯,直到找到一个 j 使得 pattern[j+1] == pattern[i],或者回溯结束(j < 0)。
    • 如果满足条件 j < 0 或者 pattern[j+1] != pattern[i],则令 j = -1(即回溯到模式串的开头)。
    • 更新 nextval[i] = j+1。

通过以上步骤,我们可以计算得到 “nextval” 数组。这样在 KMP 算法的匹配过程中,可以直接根据 “nextval” 数组进行位置的调整,从而避免不必要的回溯操作,提高算法的效率。

请注意,这里的计算 “next” 和 “nextval” 数组的方法是 KMP 算法的一种实现方式,其他实现方式可能会有所不同,但是核心思想是相似的。

这段代码实现了字符串的模式匹配算法,并计算了KMP算法中的next函数和next函数的修正值。

主要解释一下代码的实现:

  1. 首先,定义了两个函数:

    • get_next2函数用于计算模式串p的next函数。
    • get_nextval函数在已有next的基础上求next函数的修正值。
  2. 在主函数中,定义了模式串p,并输出模式串中的字符。

  3. 接着,调用get_next2函数计算模式串p的next数组,并输出结果。get_next2函数的实现如下:

void get_next2(string s,vector<int> &next)
{
	next[1]=0;
	next[2]=1;
	int k,j;
	j=2;
	while(1)
	{
		if(j>=next.size()-1)//到达倒数第二个字符,退出循环
			break;

		k=next[j];

		while(k!=0)
		{
			if(s[j]==s[k])
				break;
			else
			{
				k=next[k];//回溯
			}

		}
		next[j+1]=k+1;
		j++;

	}
}

  1. 然后,调用get_nextval函数计算模式串p的next修正值,并输出结果。get_nextval函数的实现如下:
void get_nextval(string p,vector<int> next,vector<int> &nextval) 
{
	nextval=next;//赋值 
	int j,k;
	for(j=2;j<nextval.size();j++)
	{		
			k=nextval[j];			
			
			while(p[j]==p[k])
			{				
				k =nextval[k];
				nextval[j] =k;
			}		
	}	
}

在主函数中,使用这两个函数来计算next和next修正值,并输出结果。

完整代码:

#include<iostream>
#include<vector>
#include<string>
using namespace std;
//求next函数 
void get_next2(string p,vector<int> &next);
//求next函数的修正值 
void get_nextval(string p,vector<int> next,vector<int> &nextval) ;
 
int main(void)
{
 
 
	//string p="$ababaaababaa";
	//string p="$aaaabaaaab";
	string p="$aaaaaab";
	
	cout<<"模式串为:" <<endl;
	for(int i=1;i<=p.size()-1;i++)
		cout<<p[i]<<"  ";
	cout<<endl;
	
	//下面计算next函数 
	vector<int> next;
	next.resize(p.size());
    get_next2(p,next);
    
    //下面输出对应next函数值 
    for(int i=1;i<=next.size()-1;i++)
		cout<<next[i]<<"  ";
	cout<<endl;
	
	//下面计算next函数修正值 
    vector<int> nextval;    
    get_nextval(p,next,nextval);
    
    
	for(int i=1;i<=nextval.size()-1;i++)
		cout<<nextval[i]<<"  ";
	cout<<endl;
	return 0;
}
 
void get_next2(string s,vector<int> &next)
{
	next[1]=0;
	next[2]=1;
	int k,j;
	j=2;
	while(1)
	{
		if(j>=next.size()-1)//到达倒数第二个字符,退出循环
			break;
 
		k=next[j];
		
		while(k!=0)
		{
			if(s[j]==s[k])
				break;
			else
			{
				k=next[k];//回溯
			}
			
		}
		next[j+1]=k+1;
		j++;
		
	}
}
 
void get_nextval(string p,vector<int> next,vector<int> &nextval) 
{//在已有next的基础上,取修正值;
//不像课本上那样混为一谈。 
	nextval=next;//赋值 
	int j,k;
	for(j=2;j<nextval.size();j++)
	{		
			k=nextval[j];			
			
			while(p[j]==p[k])
			{				
				k =nextval[k];
				nextval[j] =k;
			}		
	}
	
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张謹礧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值