KMP算法

M_S_D_N 2009-09-03 05:45:24
大学学过,还了老师,重新看《算法导论》中的KMP算法,自己实现了一个具体代码,觉得大体正确,但不知道怎么严格证明这个代码的正确性,请大家不吝赐教。
代码如下:

#include <string>

// 返回模式字符串在源字符串中第一次出现的位置
int KMP0(
char const *szP, // 模式字符串
char const *szS // 源字符串
) ;

int main(int argc, char ** argv)
{
char szP[] = "ababcabcab" ; // 模式字符串
char szS[] = "abababababcabcabcab" ; // 源字符串
int n = KMP0(szP, szS) ;

return 0 ;
}

int KMP0(char const *szP, char const *szS)
{
int nRes = -1 ;
int nLen = strlen(szP) ;
int * parnPS = new int[nLen] ;
parnPS[0] = 0 ;

int nState = 0 ;

int i ;
char c ;
for (i = 0 ; (c = szS[i]) != 0 ; ++ i)
{
for ( ; ; )
{
if (c != szP[nState])
{
if (nState == 0)
break ;
else
nState = parnPS[nState - 1] ;
}
else
{
if (nState > 0)
{
int nPrevState = parnPS[nState - 1] ;
if (c == szP[nPrevState])
parnPS[nState] = nPrevState + 1 ;
else
parnPS[nState] = 0 ;
}

++ nState ;
if (nState == nLen)
{
nRes = i - nLen + 1 ;
goto exit ;
}

break ;
}

}
}

exit:
delete [] parnPS ;
parnPS = NULL ;

return nRes ;
}

...全文
474 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
selooloo 2009-09-04
  • 打赏
  • 举报
回复
感觉用next函数来得简单些吧
baihacker 2009-09-04
  • 打赏
  • 举报
回复
匹配算法大概有三种,基于前缀,后缀,子串的。
用前缀专业一些,next函数是说如果失败应该产生的位移,失败函数也是说失败时产生的位移。
其实都是一回事,只是从不同的角度看同一事物罢了。

另外,用于匹配,前缀函数还可以加强的。
M_S_D_N 2009-09-04
  • 打赏
  • 举报
回复
呵呵,理论和实践总有所差异,看导论的时候明白了前缀函数的意义,但又隐约记得大学时学的算法代码里有什么next函数,网上到处查也基本都有,而我的实现思路里没有,虽然相同的理论总是会幻化成各种各样具体的实现,多少比较怀疑我的代码。

[Quote=引用 12 楼 baihacker 的回复:]
其证明很很简单,主要是前缀函数的理解。清楚了这个,后面的就是自然的了。
[/Quote]
baihacker 2009-09-04
  • 打赏
  • 举报
回复
其证明很很简单,主要是前缀函数的理解。清楚了这个,后面的就是自然的了。
liao05050075 2009-09-04
  • 打赏
  • 举报
回复
OJ用的是黑盒测试。
M_S_D_N 2009-09-04
  • 打赏
  • 举报
回复
非常感谢楼上各位!

导论上只有对KMP算法思想正确性的证明,并且导论上给出的代码也是思想性的代码,具体的实现代码,我觉得灵活性应该很大,比如很多实现KMP算法的代码里都有index和next函数。

我现在想证明代码的正确性,我想证明方式无非黑盒、白盒,白盒应该更为准确,也应该更有难度。
那些oj上的证明方式是黑盒?还是白盒呢?

[Quote=引用 8 楼 baihacker 的回复:]
http://cs.scu.edu.cn/soj/problem.action?id=2307
上面的OJ的这个题就是直接用kmp算法,正确性证明,在导论上应该有吧
[/Quote]
chenzhp 2009-09-04
  • 打赏
  • 举报
回复
惊为天人!
baihacker 2009-09-04
  • 打赏
  • 举报
回复
http://cs.scu.edu.cn/soj/problem.action?id=2307
上面的OJ的这个题就是直接用kmp算法,正确性证明,在导论上应该有吧

//以前写的shift-or, shift-and, kmp算法
template<typename ElemType>
int MatchSO(ElemType* t, int n, ElemType* p, int m, vector<int>& result)
{
typedef unsigned long long NumberType;
const int CharSet = 128;
NumberType B[CharSet];
NumberType D = ~0;
NumberType Check = 1 << (m-1);
NumberType BIT = 1;
for (int i = 0; i < CharSet; ++i) B[i] = ~0;
for (int i = 0; i < m; ++i, BIT <<= 1) B[p[i]] &= ~BIT;
result.clear();
for (int i = 0; i < n; ++i)
{
D = (D << 1) | B[t[i]];
if ((D & Check) == 0) result.push_back(i-m+1);
}
return result.size();
}

template<typename ElemType>
int MatchSA(ElemType* t, int n, ElemType* p, int m, vector<int>& result)
{
typedef unsigned long long NumberType;
const int CharSet = 128;
NumberType B[CharSet];
NumberType D = 0;
NumberType Check = 1 << (m-1);
NumberType BIT = 1;
for (int i = 0; i < CharSet; ++i) B[i] = 0;
for (int i = 0; i < m; ++i, BIT <<= 1) B[p[i]] |= BIT;
result.clear();
for (int i = 0; i < n; ++i)
{
D = ((D << 1) | 1) & B[t[i]];
if ((D & Check) != 0) result.push_back(i-m+1);
}
return result.size();
}

template<typename ElemType>
int MatchKMP(ElemType* t, int n, ElemType* p, int m, vector<int>& result)
{
int * Prefix = new int[m];
{
Prefix[0] = -1;
for (int i = 1, F = -1; i < m; ++i)
{
while (F >= 0 && p[F+1] != p[i]) F = Prefix[F];
if (p[F+1] == p[i]) ++F;
Prefix[i] = F;
}
}
{
result.clear();
for (int i = 0, F = -1; i < n; ++i)
{
while (F >= 0 && p[F+1] != t[i]) F = Prefix[F];
if (p[F+1] == t[i]) ++F;
if (F+1 == m)
{
result.push_back(i-m+1);
F = Prefix[F];
}
}
}
delete[] Prefix;
return result.size();
}
M_S_D_N 2009-09-04
  • 打赏
  • 举报
回复
自己顶一下。
M_S_D_N 2009-09-04
  • 打赏
  • 举报
回复
NULL改成0,goto改成重新写个return就行了。
[Quote=引用 5 楼 fallening 的回复:]
引用 3 楼 m_s_d_n 的回复:
为什么不用NULL?
引用 1 楼 fallening 的回复:
不错,
可否不用goto和NULL?


编译器的问题,代码移植
[/Quote]
fallening 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 m_s_d_n 的回复:]
为什么不用NULL?
引用 1 楼 fallening 的回复:
不错,
可否不用goto和NULL?

[/Quote]
编译器的问题,代码移植
M_S_D_N 2009-09-03
  • 打赏
  • 举报
回复
OJ上应该不会直接考KMP吧,呵呵。
[Quote=引用 2 楼 liao05050075 的回复:]
去OJ做题目,如果能过题目的测试数据,那就是大体正确了。
PKU JudgeOnline:
http://162.105.81.212/JudgeOnline/
KMP相关题目:
pku 1961,pku 2406,pku 2752
[/Quote]
M_S_D_N 2009-09-03
  • 打赏
  • 举报
回复
为什么不用NULL?
[Quote=引用 1 楼 fallening 的回复:]
不错,
可否不用goto和NULL?
[/Quote]
liao05050075 2009-09-03
  • 打赏
  • 举报
回复
去OJ做题目,如果能过题目的测试数据,那就是大体正确了。
PKU JudgeOnline:
http://162.105.81.212/JudgeOnline/
KMP相关题目:
pku 1961,pku 2406,pku 2752
fallening 2009-09-03
  • 打赏
  • 举报
回复
不错,
可否不用goto和NULL?

70,022

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧