SCAU--数据结构练习--8591-- 计算next值

一.下面这段话是自己随便想想就写的,可以直接跳过,看二处。

一说到求next函数的值,相信大家都会想到kmp算法,kmp算法对学数据结构的新人来说,无疑是一个坎,如果实在看不懂的话,可以跳过,以后再来看,或许就更容易明白其中的奥妙了。

对于一般的模式匹配算法,会有很多没用的步骤运行,导致运行时间过长,kmp算法相当于优化了一般的模式匹配算法,它的高效体现在利用了类似对称的原理,省去了很多不必要的步骤。
用kmp的话,就必须要先打一个next函数值的表。
next函数是怎么打出来的呢??
相信很多人对这个问题就不是很明白。
首先根据定义的话一定会有next[1]=0;
然后分两种情况讨论:
第一种:pk=pj;
这种情况说明了什么??说明从p1到pk都和后面pj部分对应相等,说明它是符合abaab(多出中间一个),abab(没有多出)这样的形式的。
那么对于这种形式,它的next[j+1]=k+1;(根据规律,不难发现,在某处的next值,等于它的最长公共前后缀的值加1);
对于这种情况也就是next[j+1]=next[j]+1;
为什么是这样子的呢??
因为假设他现在正在判断j+1处的next的值,因为j时的最长公共前后缀已有,且所以只要这时的最长公共前后缀的个数加一就是这里的值。(其实这里我感觉解释不清楚,总之next函数的值,只要是大于1,那么它后面连着的大于1的数肯定是在前面最长公共前后缀的基础上来的)。
第二种:
pk!=pj;
对于这种情况,肯定是pk-1=pj-1;
对于这种情况,最主要的是找到最长公共前后缀。
对于此时的情况,模式串既是主串又是模式串。
假设最长的公共前后缀长度为k。
那么若找得到匹配的话(j>0)next[j]=k+1;
否则(j=0),next[j]=1;
当j不为0时,若未匹配,那么j=next【j】,将模式串向右滑动,直到找到匹配的位置,或者j==0;

next函数(有缺陷)

void get_next(SString T,int next[])
{
    next[1]=0;//初始化next数组
    int i=1,j=0;
    while(i<=T[0])//T[0]为数组T的长度
    {
        if(j==0||T[i]==T[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }

这个函数为什么会有缺陷呢??
因为这里涉及到一个重复操作的问题。
例如:主串是aaaabaaaaaab
模式串是aaaaab,因为模式串的前5个字母相同,所以next函数无疑会导致5个a都重复使用,导致了多余的过程
所以改进的代码如下:

void get_next(SString T,int next[])
{
    next[1]=0;//初始化next数组
    int i=1,j=0;
    while(i<=T[0])//T[0]为数组T的长度
    {
        if(j==0||T[i]==T[j])
        {
            i++;
            j++;
            if(T[i]!=T[j])
                next[i]=j;
            else//如果相同的话,next【i】处的值就和前面next【j】处的值相等
                next[i]=next[j];
        }
        else j=next[j];
    }
}

二.本题的题目和解法

Description 编写算法,录入多个字符串计算并验证NEXT值,输入0结束。本题目给出部分代码,请补全内容。]
#include “stdio.h”
#include “stdlib.h”
#include “iostream.h”
#define MAXSTRLEN 255 // 用户可在255以内定义最大串长
typedef unsigned char SString[MAXSTRLEN+1]; // 0号单元存放串的长度

void get_next(SString T,int next[]){
// 算法4.7
// 求模式串T的next函数值并存入数组next
// 请补全代码

}
void main(){
int next[MAXSTRLEN];
SString S;
int n,i,j;
char ch;
scanf("%d",&n); // 指定要验证NEXT值的字符串个数
ch=getchar();
for(i=1;i<=n;i++)
{
ch=getchar();
for(j=1;j<=MAXSTRLEN&&(ch!=’\n’);j++) // 录入字符串
{
S[j]=ch;
ch=getchar();
}
S[0]=j-1; // S[0]用于存储字符串中字符个数
get_next(S,next);
printf(“NEXT J is:”);
for(j=1;j<=S[0];j++)
printf("%d",next[j]);
printf("\n");
}
}

输入格式
第一行:输入n,表示有n个需计算NEXT值的字符串
第二至n+1行:每行输入一个字符串

输出格式
第1至第n行:通过计算每相应行的字符串得出的NEXT值

输入样例
4
abcdefg
aaaaab
abaabcac
aaabaaab

输出样例
NEXT J is:0111111
NEXT J is:012345
NEXT J is:01122312
NEXT J is:01231234

这题就是补充求next函数的代码,那这题就很简单了,直接拿我上面的缺陷代码复制黏贴即可。
代码如下:

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
#define  MAXSTRLEN  255                   // 用户可在255以内定义最大串长
typedef unsigned char SString[MAXSTRLEN+1];	// 0号单元存放串的长度

void get_next(SString T,int next[]){
// 算法4.7
// 求模式串T的next函数值并存入数组next
   // 请补全代码
next[1]=0;
int i=1,j=0;
while(i<=T[0])
{
    if(j==0||T[j]==T[i])
    {
        i++;
        j++;
        next[i]=j;
    }
    else j=next[j];
}
}
int main(){
int next[MAXSTRLEN];
SString S;
int n,i,j;
char ch;
scanf("%d",&n);    // 指定要验证NEXT值的字符串个数
ch=getchar();
for(i=1;i<=n;i++)
{
ch=getchar();
for(j=1;j<=MAXSTRLEN&&(ch!='\n');j++)    // 录入字符串
{
S[j]=ch;
ch=getchar();
}
S[0]=j-1;    // S[0]用于存储字符串中字符个数
get_next(S,next);
printf("NEXT J is:");
for(j=1;j<=S[0];j++)
printf("%d",next[j]);
printf("\n");
}
return 0;
}
发布了43 篇原创文章 · 获赞 26 · 访问量 3096

猜你喜欢

转载自blog.csdn.net/Leo_zehualuo/article/details/104128146