• KMP算法


    KMP算法是通过分析模式字符串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用。

    本全局匹配KMP算法针对串的堆式存储数据结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # define MAXSIZE 45  //固定next数组的长度
     
    # define OK 1
    # define ERROR 0
     
    typedef int Status;    //返回状态
     
     
    //存放匹配字符串的位置
    int indexArray[MAXSIZE] = {0};
      
    //记录匹配字符串出现的次数
    int searchIndex = 0;
     
     
    //------------------串的堆分配存储表示
    typedef struct {
        char* ch; //指针域,指向存放串值的存储空间基址
        int length; // 整型域:存放串长
    } HString;

      

    next函数值仅取决于模式串本身而和相匹配的主串无关,因此从分析器定义出发而用递推的方法求得next函数的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /*
        功能:获取next函数;
    */
    void get_next(HString* t,int* next)
    {
     
         
         int i = 1,j = 0;
         *(next+1) = 0;
         while(i<t->length)
         {
            if(j == 0 || *(t->ch+i-1) == *(t->ch+j-1))
            {
                i++;
                j++;
                *(next+i) = j;
            }
            else
                j = *(next+j);
         }
    }

      

    匹配过程中产生“失配”时,指针i不变,指针j退回到next[j]所知识的位置上重新经行比较,并且当指针j退至0时,指针id和指针j需同时加1。即若主串中的第i个字符和模式中的第1个字符不等,应从主串中的第i+1个字符起重新匹配。

    当所匹配记录相等的字符数大于或等于模式串长度时,记录当前位置,即匹配合适的位置,然后继续进行下一组的匹配。

    获取next函数算法的时间复杂度为O(m),通常模式串的长度m比主要串的长度n小得多,因此,对整个匹配算法来说是值得的。

    在一般情况下,仅有一次模式匹配的时间复杂度为O(m+n),因此全局模式匹配的时间复杂度与匹配成功次数相关。为O(m+n)*b(b次)。

    KMP算法的最大特点就是指示主串的指针不需回溯,整个匹配过程中,对主串仅需从头至尾扫描一编。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    /*
        功能:kmp算法 从pos开始,获取串s中所有匹配串t位置,存放在全局函数indexArray中<br>     初始条件:t非空,且i<=pos<=s->length
    */
     
    status Index_KMP(HString* s,HString* t,int pos)
    {
        //处理非法输入<br>    
        if(!t || pos>1 || pos> s->length) <br>       return ERROR;
        //清空
        for(int k =0;k<MAXSIZE;k++)
        {
            indexArray[k] = 0;
        }
        searchIndex = 0;
         
        //得到next数组
        int j,next[MAXSIZE] = {};
        get_next(s,next);
         
        if (pos < 0 || pos > s->length)
            exit(0);
        int sLength = s->length;
        int tLength = t->length;
        int i = pos-1;
         j = 0;
     
        while(i<= sLength && j<=tLength)
        {
            if(j == 0 ||*(s->ch + i) == *(t->ch + j))
            {  
                ++i;
                ++j;
                 
                <span style=""><strong>if(j>= tLength)</strong></span>
                {
                    indexArray[searchIndex] = i-tLength+1;
                    searchIndex++;
                      
                }
            }
            else{
                j = *(next+j);
            }
        }<br>  return OK;
    }

      高亮显示区域应为if(j== tLength) 。如果写成大于等于,当主串最后位置出现匹配的字符串,即给下列测试代码中的S1赋值为abaabc时,程序给数值赋值后,i继续自增加,造成最后输出结果为1 9 17 25 26。因此,应将if(j>= tLength)改成if(j== tLength)

    测试如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        HString S1;
    InitHString(&S1);
    AssigHString(&S1,"abaabc");
     
    HString S;
    InitHString(&S);
    AssigHString(&S,"abaabcd abaabcf abaabcj abaabck");
     
    Index_KMP(&S,&S1,1);
    printf("S1在S中的出现次数:%d ",searchIndex    );
     
     
    for(int i=0;i<searchIndex;i++)
        printf("%d  ",indexArray[i]);
    printf(" ");   

     显示结果为:1 9 17 25 

    总结,细心调试,同时要增强代码的健壮性。

     
     
     
    标签: 算法
  • 相关阅读:
    jsp页面的基本语法
    servlet转发与重定向
    servlet配置及其生命周期
    Java--普通代码块静态代码块执行顺序
    Maven简述
    JDBCTemplate
    AOP--Aspect Oriented Programming
    SpringMVC---简单练手项目
    SpringMVC---进阶篇
    SpringMVC---基础篇(2)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3812460.html
Copyright © 2020-2023  润新知