c#实现KMP算法的优化

KMP算法是有三位前辈提出来的一个模式匹配算法,也就是从一个字符串中查找子串的算法,类似C#里面 indexOf ()函数的功能。

如果利用普通的匹配算法去查找子串,最坏的情况下算法复杂度是O((n-m+1)*m) n代表的主串的长度,m代表的是子串的长度,很显然这个算法比较低效。

所以就有大神们发明了KMP算法,它的原理是比普通的匹配算法节省了比对步骤,如主串m=”abcababca”,子串s=”abcabx”,前5个字符是相同的第6个字符不等,那么可以判断子串s中的第一个字符和主串中的第二个,第三个字符也不相等。KMP算法正是省略这些可以判断步骤达到优化匹配算法的目的。

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KMP
{
    class Program
    {
        //计算出子串返回的next数组,当子串不匹配时根据next数组值进行回溯
        static void GetNext(string p, int []next){
            int len = p.Length;
            int i = 0;
            int j = -1;
            next[0] = -1;
            while (i < len)
            {
                if (j == -1 || p[i] == p[j]){
                    ++j;
                    ++i;
                    next[i] = next[j];
                }
                else{
                    j = next[j];//若字符不相同,则j值回溯
                }
            }
        }

        static int Main(string[] args)
        {
            string str = "abccc aabb";
            string sub = "abb";
            int []next = new int[100];
            //计算出子串返回的next数组
            GetNext(sub, next);
            int i = 0;
            int j = 0;
            while (i < str.Length && j < sub.Length) {
                if (j == -1 || str[i] == sub[j] )
                {
                    ++i;
                    ++j;
                }
                else
                    j = next[j];//j回溯到合适的位置
            }
            if (j == sub.Length)
            {
                Console.WriteLine(i - j);
                Console.ReadKey();
                return i - j;
            }
            return 0;
        }
    }
}
  

KMP算法的优化:

后来有人发现上面的KMP算法还是有缺陷的,比如主串m=”aaaabcde” ,子串s=”aaaaax”,由于子串的前面4个字符和主串都是相等的,那么可以用首位next[1]的值去取代与它相等的字符后续的next[j]的值,因此可以对获取next数组的函数进行改良。

static void GetNext(string p, int []next){
            int len = p.Length;
            int i = 0;
            int j = -1;
            next[0] = -1;
            while (i < len)
            {
                if (j == -1 || p[i] == p[j]){
                    j++;
                    i++;
                    if (i < len && p[i] != p[j])
                        next[i] = j;
                    else
                        next[i] = next[j];//改良部分
                }
                else{
                    j = next[j];
                }
            }
        }