数据结构学习【串 顺序结构 KMP和KMP改进实现 C++】

数据结构学习【串 顺序结构 KMP C++】

本次实现的是串的顺序存储结构。

串的实现方式

串的实现方式可以分为3种。
① 定长顺序存储表示(本文的实现方式)
即固定大小

typedef struct {
    char ch[MaxSize];
    int length;
}SString;

②堆分配存储表示
即动态分配

typedef struct {
    char *ch;
    int length;
}HString;

③块链存储表示

typedef struct StringNode{
    char ch[4];   	//每个结点多存几个字符,提高存储密度
    struct StringNode *next;
}StringNode,*String;

KMP理解

推荐一个KMP算法求next数组代码实现的讲解视频。
求next数组代码实现的讲解视频

code

#include <iostream>
using namespace std;
#define MaxSize 255

//采用定长顺序存储实现串

// ADT
//最小操作子集
// StrAssign(&T,chars) 赋值操作。把串T赋值为chars
// StrCompare(S,T) 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
// StrLength(S) 求串长。
// SubString(&Sub,S,pos,len) 求子串。用sub返回串S的第pos个字符起长度为len的子串
// Concat(&T,S1,S2) 串联接。用T返回由S1、S2连接而成的新串
//其他操作
// StrCopy(&T,S) 复制操作。由串S复制得到串T
// StrEmpty(S) 判空操作
// ClearString(S)清空操作。将串清为空串
// DestroyString(&S) 销毁串。将串S销毁
// Index(S,T) 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
// Index_KMP(S,T) 用KMP算法实现定位操作

typedef struct {
    char ch[MaxSize];
    int length;
}SString;

//最小操作子集
// 赋值操作。把串T赋值为chars
bool StrAssign(SString &T,char* chars);
// 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T); 
// 求串长。
int StrLength(SString S); 
// 求子串。用sub返回串S的第pos个字符起长度为len的子串
bool SubString(SString &Sub,SString S,int pos,int len); 
// 串联接。用T返回由S1、S2连接而成的新串
bool Concat(SString &T,SString S1,SString S2);

//其他操作
// 求char*字符串长度
int CharsLength(char* chars);
// 输出串
void PrintString(SString S);
// 复制操作。由串S复制得到串T
bool StrCopy(SString &T,SString S); 
// 判空操作
bool StrEmpty(SString S); 
// 清空操作。将串清为空串
bool ClearString(SString S);
// 销毁串。将串S销毁
bool DestroyString(SString &S); 
// 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
int Index(SString S,SString T);
// 用KMP算法实现定位操作
int IndexKMP(SString S,SString T); 
// 用改进的KMP算法实现定位操作
int IndexKMPPlus(SString S,SString T); 
// 求模式串T的next数组
void GetNext(SString T,int next[]); 
// 求模式串T的next数组(改进算法)
void GetNextVal(SString T,int nextVal[]); 


int main(){
    char tmp1[]="abcd";
    char tmp2[]="abce";
    SString S1;
    StrAssign(S1,tmp1);
    SString S2;
    StrAssign(S2,tmp2);
    printf("S1:");
    PrintString(S1);
    printf("\n");
    printf("S2:");
    PrintString(S2);
    printf("\n");
    //比较
    printf("比较结果:%d\n",StrCompare(S1,S2));
    // 截取子串
    SString sub;
    SubString(sub,S1,2,3);
    printf("sub:");
    PrintString(sub);
    printf("\n");
    // 联结两个串为新串
    SString concat;
    Concat(concat,S1,S2);
    printf("concat:");
    PrintString(concat);
    printf("\n");
    // 定位
    int idx=0;
    idx=Index(S1,sub);
    printf("定位结果:%d\n",idx);
    // KMP定位
    idx=IndexKMP(S1,sub);
    printf("KMP定位结果:%d\n",idx);
    idx=IndexKMPPlus(S1,sub);
    printf("改进的KMP定位结果:%d\n",idx);
    system("pause");
}

//最小操作子集
// 赋值操作。把串T赋值为chars
bool StrAssign(SString &T,char* chars){
    if(CharsLength(chars)>MaxSize-1)//如果char字符数组大于MaxSize-1,则返回错误
        return false;              //(这里采用王道书上的方法,第零位不放元素,所以最多存储MaxSize-1个元素)
    T.length=CharsLength(chars);
    for(int i=1;i<=T.length;i++){
        T.ch[i]=*(chars+i-1);
    }   
    return true;
}

// 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T){
    for(int i=1;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;
}
// 求串长。
int StrLength(SString S){
    return S.length;
}
// 求子串。用sub返回串S的第pos个字符起长度为len的子串
bool SubString(SString &Sub,SString S,int pos,int len){
    if(pos+len-1>S.length)
        return false;
    Sub.length=len;
    for(int i=1;i<=len;i++)
        Sub.ch[i]=S.ch[pos+i-1];
    return true;
}
// 串联接。用T返回由S1、S2连接而成的新串
bool Concat(SString &T,SString S1,SString S2){
    if(S1.length+S2.length>MaxSize-1)
        return false;
    T.length=S1.length+S2.length;
    for(int i=1;i<=S1.length;i++){
        T.ch[i]=S1.ch[i];
    }
    for(int i=1;i<=S2.length;i++){
        T.ch[S2.length+i]=S2.ch[i];
    }
    return true;
}

//其他操作
// 求char*字符串长度
int CharsLength(char* chars){
    int length=0;
    while(chars[length]) length++;
    return length;
}
// 输出串
void PrintString(SString S){
    for(int i=1;i<=S.length;i++){
        printf("%c",S.ch[i]);
    }
}
// 复制操作。由串S复制得到串T
bool StrCopy(SString &T,SString S){
    T.length=S.length;
    for(int  i=1;i<=S.length;i++){
        T.ch[i]=S.ch[i];
    }
    return true;
}
// 判空操作
bool StrEmpty(SString S){
    if(S.length==0) return true;
    else return false;
}
// 清空操作。将串清为空串
bool ClearString(SString S){
    S.length=0;
    return true;
}
// 定位操作。若子串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
// 朴素算法
int Index(SString S,SString T){
    int i=1,sl=S.length,tl=T.length;
    SString sub;
    while(i<=sl-tl+1){
        SubString(sub,S,i,tl);
        if(StrCompare(sub,T)!=0) i++;
        else return i;
    }
    return 0;

}
// 用KMP算法实现定位操作
int IndexKMP(SString S,SString T){
    int i=1,j=1;
    int next[T.length+1];
    GetNext(T,next);
    while(i<=S.length&&j<=T.length){
        if(j==0||S.ch[i]==T.ch[j]){
            i++;
            j++;//继续比较后继字符
        }else{
            j=next[j];//模式串向右移动
        }
    }
    if(j>T.length)
        return i-T.length;//匹配成功
    else
        return 0;//匹配失败
}
// 用改进的KMP算法实现定位操作
int IndexKMPPlus(SString S,SString T){
    int i=1,j=1;
    int nextVal[T.length+1];
    GetNextVal(T,nextVal);
    while(i<=S.length&&j<=T.length){
        if(j==0||S.ch[i]==T.ch[j]){
            i++;
            j++;//继续比较后继字符
        }else{
            j=nextVal[j];//模式串向右移动
        }
    }
    if(j>T.length)
        return i-T.length;//匹配成功
    else
        return 0;//匹配失败
}
// 求模式串T的next数组
void GetNext(SString T,int next[]){
    int i=1,j=0;
    next[1]=0;
    while(i<T.length){
        if(j==0||T.ch[i]==T.ch[j]){
            i++;j++;
            next[i]=j;
        }else{
            j=next[j];
        }
    }
}
// 求模式串T的next数组(改进算法)
void GetNextVal(SString T,int nextVal[]){
    int next[T.length+1];
    GetNext(T,next);
    nextVal[1]=0;
    for(int i=2;i<=T.length;i++){
        if(T.ch[next[i]]==T.ch[i])
            nextVal[i]=nextVal[next[i]];
        else
            nextVal[i]=next[i];
    }
}

运行结果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 首先,KMP算法是一种字符匹配算法,它的核心是通过预处理模式,得到一个next数组,用于在匹配过程快速跳过已经匹配过的部分。 在创建顺序时,我们需要定义一个结构体来表示顺序,包含一个字符数组和一个整型变量表示的长度。在实现KMP算法时,我们需要预处理模式,计算出next数组。优化next数组的方法是通过递归计算前缀和后缀的最长公共前缀长度,避免重复计算。 具体实现步骤如下: 1. 定义顺序结构体,包含字符数组和长度变量。 2. 实现KMP算法,预处理模式,计算出next数组。 3. 优化next数组,通过递归计算前缀和后缀的最长公共前缀长度,避免重复计算。 4. 在匹配过程,利用next数组快速跳过已经匹配过的部分,提高匹配效率。 总之,KMP算法是一种高效的字符匹配算法,通过预处理模式,得到一个next数组,用于在匹配过程快速跳过已经匹配过的部分。在实现KMP算法时,需要注意优化next数组的方法,避免重复计算,提高匹配效率。 ### 回答2: KMP算法是一种字符匹配算法,它的核心思想是利用已匹配成功的部分信息,来避免在不必要的地方做重复的比较。在KMP算法,next数组是重要的组成部分,它存储了模式的前缀最长的相等的前缀和后缀的长度。 创建顺序实现KMP模式匹配,可以通过以下步骤: 1.创建一个顺序,可以使用数组或者类似于字符的方式实现。 2.读入模式和文本,将它们分别存入两个顺序。 3.通过next数组,优化模式的匹配。next数组的计算过程可以采用递归或迭代的方式实现。 4.在匹配时,从文本的第一个字符开始,依次比较模式的字符和文本的字符,如果匹配则继续比较下一个字符。如果不匹配,就利用next数组跳过已经匹配成功的部分,继续向后匹配。 5.如果匹配成功,则返回匹配的位置;否则继续比较,直到文本的所有字符都比较完毕。 优化next数组的计算,可以通过以下步骤: 1.初始化next数组,将第一个元素设为0,第二个元素设为1。 2.从第3个元素开始,依次比较前一个元素和模式的前缀后缀。 3.如果相同,则将next数组的元素赋值为前一个元素的值加1;否则继续比较下一个前缀和后缀。 4.如果没有相同的前缀和后缀,则将next数组的元素赋值为0。 5.重复以上步骤,直到计算出next数组所有的元素。 通过以上步骤,我们就可以创建顺序实现KMP模式匹配优化next数组。这个算法可以有效地提高匹配的效率,节约时间和空间。 ### 回答3: KMP模式匹配算法是一种高效的字符匹配算法,它的核心在于构建next数组。而优化next数组的过程,可以通过创建顺序数据结构实现。 首先,我们需要了解什么是顺序顺序是一种基于数组的线性数据结构,可以用来存储字符序列。我们可以通过封装数组的方式,添加一些操作方法来实现顺序的创建。具体来说,我们可以定义如下的结构体: ``` typedef struct SeqString { char* data; // 数据存储区 size_t length; // 的长度 } SeqString; ``` 其,`data`成员用于存储的数据,`length`表示的长度。接下来,我们可以定义创建顺序的函数: ``` SeqString* createSeqString(char* str, size_t len) { SeqString* s = (SeqString*)malloc(sizeof(SeqString)); s->data = (char*)malloc((len + 1) * sizeof(char)); memcpy(s->data, str, len); s->data[len] = '\0'; s->length = len; return s; } ``` 在创建顺序之后,我们可以对其进行遍历,构建next数组。KMP模式匹配算法的next数组表示模式,以每个位置为结尾的子串,前缀和后缀相等的最大长度。为了构建next数组,我们可以采用两个指针i和j,分别指向模式的第一个字符和第二个字符,并通过遍历模式的方式,依次计算得到next数组。 具体的算法流程如下: 1. 初始化i=0,j=-1,next[0]=-1 2. 判断j是否小于0或者s[i] == s[j],如果满足,则令i=i+1,j=j+1,next[i] = j 3. 如果s[i] ≠ s[j],则更新j=next[j] 4. 重复进行步骤2和3,直到i等于模式的长度为止 通过这种方式构建得到的next数组,可以在模式匹配过程实现更高效的匹配。具体的匹配过程,可以采用next数组计算当前的模式与主的匹配偏移量,通过不重复的移动主和模式的方式,来实现快速的匹配。 总的来说,优化next数组的过程是非常重要的,可以大大提升KMP模式匹配算法的效率。通过创建顺序数据结构,我们可以方便地实现这一优化过程,得到更高效的字符匹配算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值