数据结构 朴素算法与kmp算法

朴素算法

算法描述

对主串的每一个字符作为子串的开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,知道匹配成功,或者全部遍历完成为止。

实现代码

假设主串S与要匹配的子串T的长度存在S[0]与T[0]中。
实现代码如下 :

//朴素算法代码实现

//返回子串T在主串S中第pos个字符后的为止。若不存在,则函数返回值为0。
//T非空,1<=pos<=StrLength(S)
int index( String S, String T, int pos )
{
    
    
    //i用于主串S中当前位置下标,若pos不为1,则从pos位置开始匹配
    int i = pos;

    //j用于子串T中当前位置下标值
    int j = 1;

    //若i小于S长度且j小于T长度时循环
    while( i <= S[0] && j <= T[0] )
    {
    
    
        //两字母相等则继续
        if( S[i] == T[j] )
        {
    
    
            ++i;
            ++j;
        }
        else//若两字母不相等,则指针后退重新开始匹配
        {
    
    
            i = i-j+2; //i退回到上次匹配首位的下一位
            j = 1; //j退回到子串的首位
        }
    }

    if( j>T[0] )
        return i-T[0];
    else
        return 0;
}

时间复杂度

n为主串的长度,m为子串的长度,则根据等概率原则,平均是(n+m)/2次查找,时间复杂度为O( n + m )。

KMP算法

KMP模式匹配算法实现

计算next数组

//kmp模式匹配算法
//计算next数组

//通过计算,返回子串T的next数组
void get_next( String T, int *next )
{
    
    
    int i, j;
    i = 1;
    j = 0;
    next[1] = 0;

    //此处T[0]表示子串T的长度
    while( i<T[0] )
    {
    
    
        if( j==0 || T[i]==T[j] ) //T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
        {
    
    
            ++i;
            ++j;
            next[i] = j;
        }
        else
            j = next[j]; //字符不相等,则j值回溯
    }
}

kmp模式实际匹配返回下标算法实现

//kmp模式匹配算法
//返回下标

//返回子串T在主串S中第pos个字符后的位置。若不存在,则返回值为0。
int Index_KMP ( String S, String T, int pos )
{
    
    
    //i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配
    int i = pos;
    
    //j用于子串T中当前位置下标值
    int j = 1; 
    
    //定义next数组
    int next[255];
    //得到next数组
    get_next( T, next );
    
    while( i<=S[0] && j<=T[0] )
    {
    
    
        if( j==0 || T[i]==T[j] )
        {
    
    
            ++i;
            ++j;
            
        }
        else
            j = next[j];
    }
    
    if( j>T[0] )
        return i-T[0];
    else
        return 0;
}

KMP模式匹配算法改进

计算nextval数组

//kmp模式匹配算法改进
//计算nextval数组

void get_nextval( String T, int *nextval )
{
    
    
    int i, j;
    i = 0;
    j = 1;
    next[1] = 0;

    while( i<T[0] )
    {
    
    
        if( j==0 || T[i]==T[j] )
        {
    
    
            ++i;
            ++j;
            if( T[i] != T[j] ) //在kmp模式算法计算next数组中,next[i]=j
                nextval[i] = j; //如果当前字符与next[i]值所指字符不同,则nextval[i]=next[i],即将对应next值照抄
            else
                nextval[i] = nextval[j]; 如果当前字符与next[j]值所指字符相同,则nextval[i]=nextval[enxt[i]] = nextval[j]
        }
        else
        {
    
    
            j = next[j];
        }
    }
}

实际匹配算法实现

只需将“get_next(T,next)"改为”get_nextval(T,next)"即可。

KMP模式改进算法总结

在计算出next数组的同时,如果a位字符与它next值指向的b位字符相等,则该a位字符的nextval值就指向b位的nextval值。如果不等,则a位的nextval值指向自己a位的next值。

猜你喜欢

转载自blog.csdn.net/m0_46161051/article/details/115702905