KMP算法的详解 https://www.cnblogs.com/yjiyjige/p/3263858.html(很良心,很详细)
求next[]数组时,其实也是KMP配,只不过原串和匹配穿是同一个串。
生成PI的工具------y-cruncher
y-cruncher,计算圆周率等数学常数的软件,创造了计算圆周率的世界纪录
使用方法
- 下载解压,找到exe文件,并打开。
- 数字化操作,选择0(生成派),再选择0(单线程),在选择生成PI的大小(视情况).
- 之后PI会在y-cruncher文件夹中的
文件夹中生成。
C++借助string实现代码
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
void get_next(string T, int next[])
{
int i=0,j=-1;
next[0]=-1;
while (i<T.length())
{
if(j==-1||T[i]==T[j])
{
++i;
++j;
next[i]=j;
}
else j=next[j];
}
}
int Index_KMP(string S,string T,int pos)
{
/**利用模式串T的next函数求T在主串S的第pos个字符之后的位置KMP算法
其中,T费控,0<=pos+1<=StrLength(S)-1*/
int i = pos, j = -1;
int next[T.length()+1];
get_next(T,next);
while(i<(int)S.length() && j<(int)T.length())
{
if(j==-1||S[i]==T[j])
{
++i;
++j;
}
else j=next[j];
}
if(j==(int)T.length()) return i-T.length();
else return 0;
}
int main()
{
string data,b;
cout<<"输入你要寻找的字串:";
cin>>b;
ifstream infile;
infile.open("file.dat");
infile >> data;
cout<<"在Pi小数点后"<<Index_KMP(data,b,-1)-2<<"位";
infile.close(); // 关闭打开的文件
return 0;
}
几点说明:
- string.length()返回的是unsigned类型的字符的长度。
- unsigned与int比较时,会把int转换成unsigned,在计算机中用补码比较,正数的int与unsigned的机器码是相同的,但是负数会出问题(详细原理参考计算机系统基础),所以需要强制类型转换。
- 把PI文件改为file.dat放入与cpp文件一样的目录下。或者infile.open(“”)详细的路径名。
- 实测string头文件可以不要,但参考之前的教材,string类需要引用string头文件。
效果简单展示

如果想自己写串的底层实现,参考以下代码:
C语言语法底层实现
Base.h
//base.h
//-----公用的常量和类型----------
#include<stdio.h>
#include<stdlib.h>
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
String.h
//string.h
//字符串的基本操作
//---------串的堆分配存储表示----------
typedef struct
{
char *ch; //若是非空串,则按串长分配空间,否则ch为NULL
int length; //串的长度
char& operator[](int i)
{
if( i >= length )
{
printf("越界");
// 返回第一个元素
return ch[0];
}
return ch[i];
}
} String;
//--------串基本操作的函数原型说明--------
//生成一个其值等于chars的串
Status StrAssign(String &T, char *chars)
{
int i;
if(T.ch)
free(T.ch); //释放T的原有空间
for(i = 0; *(chars+i); ++i) ; //求chars的长度i
if(!i)
{
T.ch = NULL;
T.length = 0;
}
else
{
if(!(T.ch = (char *)malloc(i * sizeof(char))))
exit(OVERFLOW);
T.length = i;
for(i = 0; i <= T.length; i++)
{
T.ch[i] = chars[i];
}
}
return OK;
}//StrAssign
//返回串内元素个数,串长度
int StrLength(String S)
{
return S.length;
}//StrLength
//字符串比较,若S>T,则返回>0;若S=T,则返回=0;若S<T,则返回<0;
int StrCompare(String S, String T)
{
int i;
for(i = 0; i < S.length && i < T.length; ++i)
if(S.ch[i] != T.ch[i])
return S.ch[i] - T.ch[i];
return S.length - T.length;
}
//将串S清空
Status ClearString(String &S)
{
if(S.ch)
{
free(S.ch);
S.ch = NULL;
}
S.length = 0;
return OK;
}//ClearString
//用T返回由S1和S2连接而成的新串
Status Concat(String &T, String S1, String S2)
{
if(T.ch)
free(T.ch); //释放旧空间
if(!(T.ch = (char*)malloc((S1.length + S2.length) * sizeof(char))))
exit(OVERFLOW);
int i;
for(i = 0; i < S1.length; i++)
T.ch[i] = S1.ch[i];
T.length = S1.length + S2.length;
int j;
for( i = 0, j = S1.length; j < T.length; j++, i++)
T.ch[j] = S2.ch[i];
T.ch[T.length] = '\0';
return OK;
}//Concat
//初始条件:串S存在,1<=pos<=StrLength(S) 且 0<=len<=StrLength(S)-pos+1
//用Sub返回串S的第pos个字符起长度为len的子串
Status SubString(String &Sub, String S, int pos, int len)
{
if(pos < 1 || pos > S.length || len < 0 || len > S.length - pos + 1)
return ERROR;
if(Sub.ch)
free(Sub.ch);
if(!len)
{
Sub.ch = NULL;
Sub.length = 0;
}
else
{
Sub.ch = (char *)malloc(len * sizeof(char));
int i;
for(i = 0; i < len; i++)
{
Sub.ch[i] = S.ch [pos + i - 1];
Sub.length = len;
}
S.ch[S.length] = '\0';
return OK;
}
return OK;
}//SubSting
//判空
Status StrEmpty(String S)
{
if(S.length == 0)
return TRUE;
else
return FALSE;
}//StrEmpty
//串复制
Status StrCopy(String &T, String S)
{
if(!(T.ch = (char*)malloc(S.length * sizeof(char))))
exit(OVERFLOW);
T.ch = S.ch;
T.length = S.length;
return OK;
}//StrCopy
//若主串S中存在和串T相同的子串,则返回它在主串中的
//第pos个字符之后的第一次出现的位置,否则函数值为0
Status Index(String S, String T, int pos)
{
if(pos >= 0)
{
String Sub;
int n, m;
n = StrLength(S);
m = StrLength(T);
int i = pos;
while(i <= (n-m+1))
{
SubString(Sub, S, i, m);
if(StrCompare(Sub, T) != 0)
++i;
else
return i;
}//while
}//if
return 0;
}//Index
//初始条件:串S存在,1<=pos<=StrLength(S)+1
//操作结果:在串S的第pos个字符之前插入串T
Status StrInsert(String &S, int pos, String T)
{
if(pos < 1 || pos > S.length + 1) //pos不合法
return ERROR;
if(T.length) //T非空,则重新分配空间,插入T
{
if(!(S.ch = (char *)realloc(S.ch,(S.length + T.length) * sizeof(char))))
exit(OVERFLOW);
int i;
for(i = S.length-1; i >= pos-1; --i) //为插入T而腾出位置
S.ch[i+T.length] = S.ch[i];
for(i = 0; i < T.length; i++) //插入T
S.ch[pos+i] = T.ch[i];
S.length += T.length;
S.ch[S.length] = '\0';
}
return OK;
}//StrInsert
//初始条件:串S存在,1<=pos<=StrLength(S)-len+1
//操作结果:从串S中删除第pos个字符起长度为len的子串
Status StrDelete(String &S, int pos, int len)
{
if(pos < 1 || pos > (StrLength(S)-len+1)) //pos不合法
return ERROR;
if(S.length) //T非空,则重新分配空间,插入T
{
int i;
for(i=pos-1; i < (StrLength(S)-len+1); i++)
S.ch[i] = S.ch[len+i];
S.length -= len;
S.ch[S.length] = '\0';
}
return OK;
}//StrInsert
//初始条件:串S,T,V存在,T是非空串
//操作结果:用V替换主串S中出现的所有与T相等的不重叠的子串
Status Replace(String &S, String T, String V)
{
int i;
for(i = 0; i < (StrLength(S)-StrLength(T)); i++)
{
int j = Index(S, T, 0);
if(j)
{
StrDelete(S, j, StrLength(T));
StrInsert(S, j-1, V);
}
}
return OK;
}//Replace
//销毁串
Status DestroyString(String &S)
{
if(!S.ch);
else
{
free(S.ch);
S.ch = NULL;
S.length = 0;;
}
return OK;
}//DestroyString
void get_next(String T, int next[])
{
int i=0,j=-1;
next[0]=-1;
while (i<T.length)
{
if(j==-1||T[i]==T[j])
{
++i;
++j;
next[i]=j;
}
else j=next[j];
}
}
int Index_KMP(String S,String T,int pos)
{
/**利用模式串T的next函数求T在主串S的第pos个字符之后的位置KMP算法
其中,T费控,0<=pos+1<=StrLength(S)-1*/
int i = pos, j = -1;
int next[T.length+1];
get_next(T,next);
while(i<S.length && j<T.length)
{
if(j==-1||S[i]==T[j])
{
++i;
++j;
}
else j=next[j];
}
if(j==T.length) return i-T.length;
else return 0;
}
main.cpp
#include"Base.h"
#include"String.h"
#define N 100000
int main()
{
int i;
String S,T;
printf("输入你要查找的字串:");
char *c;
c=(char *)malloc(100000*sizeof(char));
scanf("%s",c);
StrAssign(T, c);
FILE *fp;
if((fp=fopen("file.dat","r"))==NULL)
{
printf("can't open file!\n");
exit(0);
}
if((fgets(c,N,fp))!=NULL)
{
c[N]='\0';
StrAssign(S, c);
printf("在Pi小数点后%d位",Index_KMP(S,T,-1)-2);
}
else printf("can't read the file\n");
return 0;
}
BUG:规范编码应该有fclose(fp),但是加上后运行会卡死,不知道深层次原因,在网上找可能是fopen并没有完全打开,求大神指导。