数据结构与算法---复习:顺序表字符串的KMP算法实现

数据结构与算法—复习:顺序表字符串的KMP算法实现

首先感叹一下KMP算法中求解next数组的算法之精妙:

int* findNext(PSeqString s){
    int* next = (int*)malloc(sizeof(s->n)); //分配适合大小的next数组空间
    int i = 0 , k = -1;  //初始化开始的值
    next[0] = -1;  //next[0] 一定是 -1  有些地方写的是 0
    while(i < s->n - 1){ //求解第i+1个下标的next数组值
        while(k >= 0 && s->c[i] != s->c[k])
            k = next[k];
        i++;k++;
        next[i] = k;
    }
    return next;
}

下面给出全套代码:

/**
 * 程序说明:顺序表实现字符串
 * 1.创建一个空的字符串
 * 1.3. 判断字符串是否为空
 * 2.创建一个
 * 3.删除指定下标的字符
 * 4.在指定下标插入字符
 * 5.NULL
 * 6.返回指定下标的字符
 * 7.拼接字符串
 * 8.返回某字符串在主字符串中第一次出现的位置
 */
#include <stdio.h>
#include <malloc.h>

/**
 * 字符串类型的定义,与顺序表一致,替换了其中DataType
 */
struct SeqString{
    int MAXNUM;  //字符串最大长度
    int n;  //当前字符串长度
    char* c;  //字符串内容数组
};
typedef struct SeqString* PSeqString;

/**
 * 1.创建一个空的字符串
 * @param m
 * @return
 */
PSeqString createNullStr_seq(int m){
    PSeqString pstr = (PSeqString)malloc(sizeof(struct SeqString));
    if(pstr != NULL){
        pstr->c = (char*)malloc(sizeof(char)*m);
        if(pstr->c){
            pstr->MAXNUM = m;
            pstr->n = 0;
            return pstr;
        }else{
            free(pstr);
        }
    }
    printf("字符串头指针分配空间出错\n");
    return NULL;
}



/**
 * 1.2 初始化字符串数据
 * @param pstr
 * @param data
 */
void initString(PSeqString pstr,char data[],int size){
    if(pstr == NULL){
        printf("字符串为空,无法初始化\n");
        return;
    }
    for(int i = 0; i < size ;i++){
        pstr->c[i] = data[i];
        pstr->n++;
    }
    printf("初始化完成\n");
}

/**
 * 1.3 打印字符串
 * @param pstr
 */
void printString(PSeqString pstr){
    if(pstr == NULL){
        printf("字符串为空,无法打印\n");
        return;
    }
    for(int i=0;i<pstr->n;i++)
    {
        printf("%c",pstr->c[i]);
    }
    printf("\n");
}

/**
 * 1.3.判断字符串是否为空
 * @param pstr
 * @return
 */
int isNullString_seq(PSeqString pstr){
    if(pstr->n == 0)
        return 1;
    else
        return 0;
}

/**
 * 2.求子串 从第i个字符开始的后续j个
 * abcdef 中 a就是第一个(不按照下标考虑,按照考虑)
 * @param pstr
 * @param i
 * @param j
 * @return
 */
PSeqString subStr_seq(PSeqString pstr,int i,int j){
    if(pstr == NULL || isNullString_seq(pstr)){
        printf("字符串不存在或为空,无法执行求子串操作\n");
        return NULL;
    }
    /*求从s所指的顺序串第i个字符开始连续的j个字符所构成的子串*/
    PSeqString pstr_son;
    int k;
    pstr_son = createNullStr_seq(j);
    if(pstr_son == NULL) return NULL;
    if(i>0 && i<=pstr->n && j>0){
        if(pstr->n < i+j-1)
            j = pstr->n -i + 1;
        for(k=0;k<j;k++){
            pstr_son->c[k] = pstr->c[i+k-1];
        }
        pstr_son->n = j;
    }
    return pstr_son;
}
/**
 * 3.删除指定下标的字符
 * @param pstr
 * @param p
 * @return
 */
int deleteP_SeqString(PSeqString pstr,int p){
    if(pstr == NULL || isNullString_seq(pstr)){
        printf("字符串不存在或为空,无法执行删除操作\n");
        return -1;
    }
    if(p<0 || p>pstr->n){
        printf("所给下标超出字符串范围\n");
        return -1;
    }
    for(int i=p;i<pstr->n;i++){
        if(i+1 != pstr->n)
            pstr->c[i] = pstr->c[i+1];
    }
    pstr->n--;
}

/**
 * 4.在指定的下标插入字符
 * @param pstr
 * @param p
 * @param c
 * @return
 */
int insertChar(PSeqString pstr,int p,char c){
    if(pstr == NULL || isNullString_seq(pstr)){
        printf("字符串不存在或为空,无法执行插入操作\n");
        return -1;
    }
    if(p<0 || p>pstr->n){
        printf("所给下标超出字符串范围\n");
        return -1;
    }
    pstr->n++;
    for(int i = pstr->n - 1;i > p; i--){
        pstr->c[i] = pstr->c[i-1];
    }
    pstr->c[p] = c;
    return 1;
}

/**
 * 6.返回指定下标的字符
 * @param pstr
 * @param postion
 * @return
 */
char charAt(PSeqString pstr,int postion){
    if(pstr == NULL || isNullString_seq(pstr)){
        printf("字符串不存在或字符串长度为空\n");
        return '!';
    }
    return pstr->c[postion - 1];
}

/**
 * 7.拼接两个字符串
 * @param s1
 * @param s2
 * @return
 */
PSeqString concat(PSeqString s1,PSeqString s2){
    int len = s1->n+s2->n;
    int flag = 0;
    PSeqString s = createNullStr_seq(len);
    for(int i=0;i<len;i++)
    {
        if(i>=s1->n){
            s->c[i] = s2->c[flag];
            s->n++;
            flag++;
        }else{
            s->c[i] = s1->c[i];
            s->n++;
        }
    }
    return s;
}

/**
 * 8.找出子串第一次出现在主串的位置
 * @param s1
 * @param s2
 * @return
 */
int Index(PSeqString s1,PSeqString s2){
    if(s1 == NULL || isNullString_seq(s1)){
        printf("主串不存在或为空,无法执行操作\n");
        return -1;
    }
    if(s2 == NULL || isNullString_seq(s2))
        return -1;
    int p = 0;
    int mark = 1;
    for(int i=0;i<=s1->n;i++){
        if(p == s2->n){
            return (i - p);
        }
        if(s1->c[i] != s2->c[p]){
            //如果不匹配,指针回溯
            i = mark - 1;
            mark++;
            p = 0;
        }else{
            p++;
        }
    }
    return -1;
}

int* findNext(PSeqString s){
    int* next = (int*)malloc(sizeof(int) * s->n);
    next[0] = -1;
    int i = 0, k = -1;
    while(i < s->n-1) //k = 2 , i = 4 , next[3] = 1;
    {
        while(k >= 0 && s->c[i] != s->c[k])
            k = next[k];
        i++;
        k++;
        next[i] = k;
    }
    return next;
}

int KMP(PSeqString s1,PSeqString s2,int* next){
    if(s1 == NULL || isNullString_seq(s1)){
        printf("主串不存在或为空,无法执行操作\n");
        return -1;
    }
    if(s2 == NULL || isNullString_seq(s2)){
        return -1;
    }
    int i = 0 , j = 0;
    while(i < s1->n && j < s2->n)
    {
        if(j == -1 || s1->c[i] == s2->c[j]){
            i++;j++;
        }else{
            j = next[j];
        }
    }
    if(j >= s2->n)
        return i - (s2->n);
    else
        return -1;
}


int main(){
    //测试KMP算法:
    printf("测试KMP算法:\n");
    char t2[] = {'A','B','A','B','A','A','A','C','A','B','A','A'};
    char t3[] = {'A','C','A'};
    int size3 = (sizeof(t2) / sizeof(char));
    int size4 = (sizeof(t3) / sizeof(char));
    printf("%d\n",size3);
    printf("%d\n",size4);
    PSeqString test2 = createNullStr_seq(100);
    PSeqString test3 = createNullStr_seq(100);
    initString(test2,t2,size3);
    initString(test3,t3,size4);
    printString(test2);
    printString(test3);
    int* next = findNext(test3);
    for(int i=0;i<size4;i++)
    {
        printf("%d ",next[i]);
    }
    printf("\n");
    printf("KMP是否找到:%d\n",KMP(test2,test3,next));
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值