基本数据结构与算法笔记之--KMP算法

基本数据结构与算法笔记之--KMP算法

注:用于自己复习之用

KMP算法介绍:
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

在KMP算法中关键就是求解next数组的值,故此笔记主要记录next的求解过程
1.未优化的KMP版本
next[i]指的是在串p[0]~p[i-1]中最大相同的前后缀: 比如:p[0]~p[i-1]是 "aaa****aaa"(****指的是不相同的乱字符)它的前后缀为: "aaa"

/*
    next数组是这样的:
    next[i]指的是在模式串p中的index 0~i-1中最长的相同的前缀和后缀长度
*/
int *get_next(char *p){ //获取模式串p的next数组
    int p_len = strlen(p), i, k = -1;
    if(p_len == 0)
        return NULL;
    int *next = (int *)malloc(sizeof(int) * p_len);
    next[0] = -1; //初始next[0] = -1
    for(i = 1; i < p_len; i++){
        while(k != -1 && p[k] != p[i-1])
            k = next[k]; //回溯
        k++;
        next[i] = k;
    }
    return next;
}

2.优化的KMP版本
优化示例:如在 p[0]~p[i]:"aaab****aaab"在未优化版本中next[i]==3,在实际中,可优化该值,在i位置出现了失配即T[j-i]到T[j-1]与p[0]到p[i-1]相配而在T[j]与p[i]失配。按未优化的则j-=next[i]

//优化后的next
int *get_newnext(char *p){
    int p_len = strlen(p), i, k = -1;
    if(p_len == 0)
        return NULL;
    int *next = (int *)malloc(sizeof(int) * p_len);
    next[0] = -1; //初始next[0] = -1
    for(i = 1; i < p_len; i++){
        while(k != -1 && p[k] != p[i-1])
            k = next[k]; //回溯
        k++;
        if(p[i] == p[k])
            next[i] = next[k];
        else
            next[i] = k;
    }
    return next;
}

int kmp(char *T, char *p){ //主字符串T, 模式字符串p
    int T_len = strlen(T), p_len = strlen(p), i = 0, j = 0;
    int *next = get_newnext(p);
    while(i < T_len && j < p_len){ //i不回溯,j回溯
	if(j == -1 || T[i] == p[j])
	{
	    i++;
	    j++;
	}
	else
	    j = next[j];
    }
    if(j == p_len)
	return i - p_len;
    return -1;
}

void KMP(char *T, char *p){
    int i = 0, t;
    while(1){
        t = kmp(&T[i], p);
        if(t == -1)
            return;
        i += t + 1;
        printf("在index=%d处匹配成功!\n", i);
    }
}

void dispP_Str(char *p){
    int p_len = strlen(p);
    int i;
    printf("打印模式串p如下:\n");
    for(i = 0; i < p_len; i++)
        printf("%c ", p[i]);
    printf("\n");
}

void dispNext(int *next, int len){
    int i;
    printf("打印next数组如下:\n");
    for(i = 0; i < len; i++)
        printf("%d ", next[i]);
    printf("\n");
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值