KMP实现圆周率PI中找字串

本文详细介绍KMP算法,包括next数组的生成及在字符串匹配中的应用。同时介绍使用y-cruncher软件高效计算圆周率π的方法,以及如何通过C++代码在π的小数点后查找特定字符串的位置。

KMP算法的详解 https://www.cnblogs.com/yjiyjige/p/3263858.html(很良心,很详细)
求next[]数组时,其实也是KMP配,只不过原串和匹配穿是同一个串。
生成PI的工具------y-cruncher
y-cruncher,计算圆周率等数学常数的软件,创造了计算圆周率的世界纪录
使用方法

  1. 下载解压,找到exe文件,并打开。
    在这里插入图片描述
  2. 数字化操作,选择0(生成派),再选择0(单线程),在选择生成PI的大小(视情况).
  3. 之后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并没有完全打开,求大神指导。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值