原题描述
Description
编写算法,录入多个字符串计算并验证NEXT值,输入0结束。
输入格式
第一行:输入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[ i]=next[ i-1]+1,当然next[ i-1]的含义很关键。在前缀后缀连续匹配时,递推式中的next[ i-1]就是next[ i-1] ;当不匹配时,(假设有数组a[n])要将a[ i-1 ]与a[ next[ i-1] ] 匹配,若成功,则说明前缀a[1]a[2]…a[ next[ i-1] 与以a[ i-1 ]为末尾且前缀等长的后缀匹配,这种情况下递推式中next[ i-1]就是next[ next[ i-1] ] 。若仍不匹配,则需循环上述动作(就是代码中的while循环),直至next [ n ]等于0,说明在 i 前面的串中没有任何长度大于等于1的相同的前缀和后缀。根据书本95页定义此时next[ i]=1,或者也相当于next [ i-1]就是0。
PS:套娃真的恶心!书本用的是严蔚敏数据结构C语言版第二版。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
void nx(char a[])
{
int i,j,len=strlen(a+1),next[105]={0};/*因为字符串是从1开始的,
所以这里所有操作也要从1开始*/
for(i=2;i<=len;i++)
{
j=next[i-1];
while(j&&a[i-1]!=a[j])
j=next[j];
next[i]=j+1; //递推式next[i]=next[i-1]+1的更新版
}
printf("NEXT J is:");
for(i=1;i<=len;i++)//输出next函数
printf("%d",next[i]);
printf("\n");
}
int main()
{
int i,n;
char a[105][105]={0};
cin>>n;
getchar();
for(i=0;i<n;i++)
gets(a[i]+1);//规定字符串都是从1开始存放有效字符
for(i=0;i<n;i++)
nx(a[i]);
return 0;
}
总结
整个代码中就是短短几行(11行至17行)实现了上面我用接近两百字描述的算法。个人认为这类代码实现能力是很值得我们学习的(思想来自老师,代码自己复现)。有必要来捋一捋别人是怎么写出这些代码的。
先按最正常的情况来,在前缀后缀连续匹配时,递推式中的next[ i-1]就是next[ i-1] ,可以很自然写出13和16行代码。在无法连续匹配时(即a[ i-1 ]!=a[ next[ i-1]),对应的算法部分可以转换成14行的while循环,此时循环条件中没有 j !=0。直到最后,a[ i-1 ]与前面的匹配全部失败,按照定义,本来应该在16行后面直接补充一条条件赋值语句(if(j==0)next[ i]=1 else next[ i]=j+1;)。但我们应该看到当j等于0,14行的while循环将会永远进行下去,所以我们将j为真值补充进循环控制条件里。这样就写出了我们看到的短小精悍的代码。