字符串查找算法kmp

字符串查找最简单的方法就是一个一个地“滑动”查找。这样查找算法复杂度可定很高,假设pattern的长度为M,文本txt的长度为N,那么算法复杂度为O(M(n-m-1))。

KMP模式搜索算法

KMP(Knuth morris pratt)我只认识Knuth,大名鼎鼎的高纳德老头子嘛。

KMP算法的基本思想是,当“失配”的时候,利用之前已经比较过的字串信息,确定重新开始比较时pattern串的开始的位置,而不是每次都要从头开始比较。

KMP算法先预处理一下pattern串pat[],构造出来一个lps[]数组,lps的意思是longest proper prefix which is also suffix(最长前缀也是最长后缀)。对于字串pat[0...i],i取值可以是0到m,m是pat的长度。lps[i]存储的值是子模式串pat[0...i]的最大前缀后缀的长度。

   lps[i] = the longest proper prefix of pat[0..i] 
              which is also a suffix of pat[0..i]. 

Examples:
For the pattern “AABAACAABAA”, lps[] is [0, 1, 0, 1, 2, 0, 1, 2, 3, 4, 5]
For the pattern “ABCDE”, lps[] is [0, 0, 0, 0, 0]
For the pattern “AAAAA”, lps[] is [0, 1, 2, 3, 4]
For the pattern “AAABAAA”, lps[] is [0, 1, 2, 0, 1, 2, 3]
For the pattern “AAACAAAAAC”, lps[] is [0, 1, 2, 0, 1, 2, 3, 3, 3, 4]

搜索算法:

不像简单搜索方法那样一个字符一个字符的滑动搜索,我们用lps[]确定pattern串滑动的位置。下面详细说明具体怎么比较:当pat[i]和txt[i]失配的时候,pat[0...j-1]和txt[i-j+1...i-1]是匹配的。如果滑动一位去再次比较,那么这pat[0...j-1]个字符肯定不匹配了。那么应该滑动多少位呢?这是就用到lps了,这是滑动lps[j-1]位.

预处理算法:

预处理就是用pat[]求出lsp[]数组。用变量len记录当前位置字串的最长前缀的长度。初始lps[0]=0,len=0.如果pat[len]和pat[i]匹配,长度len加1,然后将len赋值给lps[i].如果pat[i]和pat[len]不匹配,如果这是len不等于0,更新len为lps[len-1].参看下面代码了解更多细节。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// naive search
void search(char* txt,char* pat)
{
    int n=strlen(txt);
    int m=strlen(pat);

    for(int i=0;i<n-m;i++)
    {
        int j;
        for(j=0;j<m;j++)
        {
            if(txt[i+j]!=pat[j])
                break;
        }
        if(j==m)
            printf("%d\n",i);
    }
}

// kmp search
void computeLPSArray(char* pat,int m,int* lps);
void KMPSearch(char* pat,char* txt)
{
    int m=strlen(pat);
    int n=strlen(txt);

    int* lps=(int*)malloc(sizeof(int)*m);
    computeLPSArray(pat,m,lps);

    int i=0;
    int j=0;
    while(i<n)
    {
        if(txt[i]==pat[j])
        {
            i++;
            j++;
        }
        if(j==m)
        {
            printf("found pattern at index %d\n",i-j);
            j=lps[j-1];
        }
        else if(i<n && pat[j]!=txt[i])
        {
            if(j!=0)
                j=lps[j-1];
            else
                i++;
        }
    }
    free(lps);
}

// compute lps array
void computeLPSArray(char* pat,int m,int* lps)
{
    int len=0;
    int i=1;
    lps[0]=0;

    while(i<m)
    {
        if(pat[i]== pat[len])
        {
            len++;
            lps[i]=len;
            i++;
        }
        else
        {
            if(len!=0)
            {
                len=lps[len-1];
            }
            else
            {
                lps[i]=0;
                i++;
            }
        }
    }
}

int main(void)
{
    char *txt = "AABAACAADAABAAABAA";
    char *pat = "AABA";
    search(txt,pat);
    printf("Hello World!\n");
    KMPSearch(pat,txt);
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值