KMP算法 --字符串匹配

子串自身存在重复部分时 

朴素匹配算法会进行很多不必要的匹配步骤


KMP算法

引入next数组(回溯函数)

表示子串各个位置j值的变化

next[j]就是第j位匹配不通过时,回溯next[j]位,j+1位再进行匹配


next数组计算时可以从第三位开始计算

因为第一位和第二位值是确定的

第一位前面没有其他字符,回溯函数的值定义为-1

第二位前面只有一个字符,回溯函数的值定义为0

第三位开始计算,如果第一位字符和第二位字符相等,next[j]=1,否则next[j]=0

第四位继续计算,

第一位=第二位 情况下(next[j]=1)

如果第二位和第三位字符也相等,next[j+1]=next[j]+1

否则,j回溯next[j]位(j=next[j])

以此类推


程序如下:



 class test
    {
        /*  
            KMP算法
            检索某字符串s在另一字符串str中,第pos位之后是否存在,存在则返回第一次出现的位置
         */
        static void Main(string[] args)
        {
            String str = "ababaaaba"; //构建主字符串
            String s = "aa";  //构建子字符串
            int pos = 4;    //检索起始的位数,最低位定义为1,表示从主字符串第一位str[0]开始检索,也就是检索整个主字符串
            int result=searchIndex(str, s, pos);  //执行匹配方法,获得结果
            switch (result){
                case -1:  
                    Console.Write("在字符串{0}中,从第{1}位起开始检索,未找到{2}",str,pos,s);
                    break;
                default:
                    Console.Write("在字符串{0}中,从第{1}位起开始检索,{2}最先出现在第{3}位", str, pos , s , result);
                    break;
            }
            Console.Read();




        }
        static int searchIndex(String str, String s, int pos)
        {
            int m = str.Length;
            int n = s.Length;
            if (m < n)
            {
                Console.Write("要检索的目标字符串长度大于被检索字符串" + '\n');
            }
            else if (pos > m || pos <= 0)
            {
                Console.Write("检索起始位置超出被检索字符串长度" + '\n');
            }
            else
            {
                int[] next = getNext(str);
                int i = pos-1;    //主字符串指针
                int j = 0;        //子字符串指针
                while (i < m && j < n)
                {
                    if (j == -1||str[i].Equals(s[j]))  //匹配成功,匹配位数+1继续循环,进行下一位的匹配
                    {
                        i++;
                        j++;
                    }
                    else
                    {
                        j = next[j]; //匹配不成功,j进行回溯,回溯的值为这一位的回溯函数值
                    }
                }
                if (j >= n) //j>=n说明子字符串全部匹配成功,也就是说在主字符串中已经找到了子字符串
                {
                    return i - n + 1;   //返回子字符串的在主字符串中首次出现的开始位置,这个位置定义和pos一样,从1开始
                }
            }
            return -1; //程序运行到这里返回-1,说明未找到子字符串
        }
        static int[] getNext(String T)         //获取字符串的next数组 记录每次匹配时从哪里开始比较 
        {
            int[] next = new int[T.Length];
            next[0] = -1;
            next[1] = 0;    //第二个元素的回溯函数值必然是0,可以证明:
            int i = 2;  //要计算next值的字符的索引
            int j = 0;  //计算next值所需要的中间变量,每一轮迭代初始时j总为next[i-1]
            while (i < T.Length)    
            { 
                if (T[i - 1] == T[j])   //迭代计算next值是从第三个元素开始的
                {   //第i位字符它的前缀首位和末尾字符相等,回溯值+1
                    next[i] = j+1;
                    i++;
                    j++;
                }
                else
                {   //如果不相等j就回溯,回溯的位数为第j位的回溯函数值
                    j = next[j];
                    if (j == -1)    //如果j == -1表示回到首位,则第i位的回溯值就是0了
                    {
                        next[i] = j + 1;
                        i++;
                        j++;
                    }
                }
            }
            return next;
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值