C# 什么';我的KMP算法的实现有什么问题? static void Main(字符串[]args) { string str=“ABC-ABCDAB-abcdabde”;//我们应该在这里添加一些文本,以便 //性能测试。 字符串模式=“ABCDABD”; 列表移位=新列表(); 秒表秒表=新秒表(); 秒表。开始(); 字符串匹配器(移位、str、模式); 秒表; WriteLine(String.Format(“原始字符串匹配器{0}”,stopWatch.appeased)); foreach(整数s换班) { Trace.WriteLine(s); } 移位。清除(); stopWatch.Restart(); int[]pi=新的int[pattern.Length]; Knuth_Morris_Pratt(移位、str、模式、pi); 秒表; WriteLine(String.Format(“Knuth_Morris_Pratt{0}”,stopWatch.appeased)); foreach(整数s换班) { Trace.WriteLine(s); } Console.ReadKey(); } 静态IList字符串匹配器(列表移位、字符串文本、字符串模式) { int lengthText=text.Length; int lengthPattern=模式长度; 对于(int s=0;s

C# 什么';我的KMP算法的实现有什么问题? static void Main(字符串[]args) { string str=“ABC-ABCDAB-abcdabde”;//我们应该在这里添加一些文本,以便 //性能测试。 字符串模式=“ABCDABD”; 列表移位=新列表(); 秒表秒表=新秒表(); 秒表。开始(); 字符串匹配器(移位、str、模式); 秒表; WriteLine(String.Format(“原始字符串匹配器{0}”,stopWatch.appeased)); foreach(整数s换班) { Trace.WriteLine(s); } 移位。清除(); stopWatch.Restart(); int[]pi=新的int[pattern.Length]; Knuth_Morris_Pratt(移位、str、模式、pi); 秒表; WriteLine(String.Format(“Knuth_Morris_Pratt{0}”,stopWatch.appeased)); foreach(整数s换班) { Trace.WriteLine(s); } Console.ReadKey(); } 静态IList字符串匹配器(列表移位、字符串文本、字符串模式) { int lengthText=text.Length; int lengthPattern=模式长度; 对于(int s=0;s,c#,algorithm,performance,string,C#,Algorithm,Performance,String,为什么我对KMP算法的实现要比简单的字符串匹配算法慢?KMP算法有两个阶段:首先构建一个表,然后根据表的内容进行搜索 朴素算法有一个阶段:它进行搜索。在最坏的情况下,它的搜索效率要比KMP搜索阶段低得多 如果KMP比naive算法慢,那么这可能是因为构建表所花费的时间比简单地搜索字符串所花费的时间要长。简单的字符串匹配通常在短字符串上非常快。在字符串搜索的BCL实现中,我们不使用像KMP这样的算法是有原因的。在设置表时,您可以使用naive算法对短字符串进行六次搜索 如果你有大量的字符串,并且你

为什么我对KMP算法的实现要比简单的字符串匹配算法慢?

KMP算法有两个阶段:首先构建一个表,然后根据表的内容进行搜索

朴素算法有一个阶段:它进行搜索。在最坏的情况下,它的搜索效率要比KMP搜索阶段低得多

如果KMP比naive算法慢,那么这可能是因为构建表所花费的时间比简单地搜索字符串所花费的时间要长。简单的字符串匹配通常在短字符串上非常快。在字符串搜索的BCL实现中,我们不使用像KMP这样的算法是有原因的。在设置表时,您可以使用naive算法对短字符串进行六次搜索

如果你有大量的字符串,并且你正在进行大量的搜索,允许你重复使用已经构建的表,那么KMP就是一个胜利。您需要通过使用该表进行大量搜索来分摊构建该表的巨大成本

而且,naive算法只在奇怪和不太可能的场景中表现不佳。大多数人在“英国伦敦白金汉宫”这样的字符串中搜索像“伦敦”这样的单词,而不是在“BANAN BANBAN BANAN BANAN BANAN bananananan…”这样的字符串中搜索像“banananana”这样的字符串。朴素搜索算法对于第一个问题是最优的,对于后一个问题是高度次优的;但为前者而不是后者进行优化是有意义的

另一种说法是:如果搜索到的字符串的长度为w,而搜索到的in字符串的长度为n,那么KMP是O(n)+O(w)。朴素算法是最坏情况O(nw),最好情况O(n+w)。但这并没有说明“常数因子”!KMP算法的常数因子远大于naive算法的常数因子。n的值必须非常大,次优部分匹配的数量必须非常大,KMP算法才能战胜极快的naive算法

这涉及算法复杂性问题。你的方法也不是很好,这也许可以解释你的结果。记住,第一次运行代码时,抖动必须将IL jit到汇编代码中在某些情况下可能比运行该方法花费更长的时间。您确实应该在一个循环中运行代码几十万次,丢弃第一个结果,并对其余结果的计时进行平均


如果你真的想知道发生了什么,你应该使用分析器来确定热点是什么。同样,如果希望得到不受jit时间影响的结果,请确保测量的是后jit运行,而不是代码jit运行。

您的示例太小,并且没有足够的重复KMP避免回溯的模式


在某些情况下,KMP可能比正常搜索速度慢

一个简单的KMPSubstringSearch实现

使用系统;
使用System.Collections.Generic;
使用System.Linq;
名称空间算法
{
类KMPSubstringSearch
{
public void KMPSubstringSearchMethod()
{
string text=System.Console.ReadLine();
char[]sText=text.ToCharArray();
字符串模式=System.Console.ReadLine();
char[]sPattern=pattern.ToCharArray();
static void Main(string[] args)
{
    string str = "ABC ABCDAB ABCDABCDABDE";//We should add some text here for 
                                           //the performance tests.

    string pattern = "ABCDABD";


    List<int> shifts = new List<int>();

    Stopwatch stopWatch = new Stopwatch();

    stopWatch.Start();
    NaiveStringMatcher(shifts, str, pattern);
    stopWatch.Stop();
    Trace.WriteLine(String.Format("Naive string matcher {0}", stopWatch.Elapsed));

    foreach (int s in shifts)
    {
        Trace.WriteLine(s);
    }

    shifts.Clear();
    stopWatch.Restart();

    int[] pi = new int[pattern.Length];
    Knuth_Morris_Pratt(shifts, str, pattern, pi);
    stopWatch.Stop();
    Trace.WriteLine(String.Format("Knuth_Morris_Pratt {0}", stopWatch.Elapsed));

    foreach (int s in shifts)
    {
        Trace.WriteLine(s);
    }

    Console.ReadKey();
}

static IList<int> NaiveStringMatcher(List<int> shifts, string text, string pattern)
{
    int lengthText = text.Length;
    int lengthPattern = pattern.Length;

    for (int s = 0; s < lengthText - lengthPattern + 1; s++ )
    {
        if (text[s] == pattern[0])
        {
            int i = 0;
            while (i < lengthPattern)
            {
                if (text[s + i] == pattern[i])
                    i++;
                else break;
            }
            if (i == lengthPattern)
            {
                shifts.Add(s);                        
            }
        }
    }

    return shifts;
}

static IList<int> Knuth_Morris_Pratt(List<int> shifts, string text, string pattern, int[] pi)
{

    int patternLength = pattern.Length;
    int textLength = text.Length;            
    //ComputePrefixFunction(pattern, pi);

    int j;

    for (int i = 1; i < pi.Length; i++)
    {
        j = 0;
        while ((i < pi.Length) && (pattern[i] == pattern[j]))
        {
            j++;
            pi[i++] = j;
        }
    }

    int matchedSymNum = 0;

    for (int i = 0; i < textLength; i++)
    {
        while (matchedSymNum > 0 && pattern[matchedSymNum] != text[i])
            matchedSymNum = pi[matchedSymNum - 1];

        if (pattern[matchedSymNum] == text[i])
            matchedSymNum++;

        if (matchedSymNum == patternLength)
        {
            shifts.Add(i - patternLength + 1);
            matchedSymNum = pi[matchedSymNum - 1];
        }

    }

    return shifts;
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace AlgorithmsMadeEasy
{
    class KMPSubstringSearch
    {
        public void KMPSubstringSearchMethod()
        {
            string text = System.Console.ReadLine();
            char[] sText = text.ToCharArray();

            string pattern = System.Console.ReadLine();
            char[] sPattern = pattern.ToCharArray();

            int forwardPointer = 1;
            int backwardPointer = 0;

            int[] tempStorage = new int[sPattern.Length];
            tempStorage[0] = 0;

            while (forwardPointer < sPattern.Length)
            {
                if (sPattern[forwardPointer].Equals(sPattern[backwardPointer]))
                {
                    tempStorage[forwardPointer] = backwardPointer + 1;
                    forwardPointer++;
                    backwardPointer++;
                }
                else
                {
                    if (backwardPointer == 0)
                    {
                        tempStorage[forwardPointer] = 0;
                        forwardPointer++;
                    }
                    else
                    {
                        int temp = tempStorage[backwardPointer];
                        backwardPointer = temp;
                    }

                }
            }

            int pointer = 0;
            int successPoints = sPattern.Length;
            bool success = false;
            for (int i = 0; i < sText.Length; i++)
            {
                if (sText[i].Equals(sPattern[pointer]))
                {
                    pointer++;
                }
                else
                {
                    if (pointer != 0)
                    {
                        int tempPointer = pointer - 1;
                        pointer = tempStorage[tempPointer];
                        i--;
                    }
                }

                if (successPoints == pointer)
                {
                    success = true;
                }
            }

            if (success)
            {
                System.Console.WriteLine("TRUE");
            }
            else
            {
                System.Console.WriteLine("FALSE");
            }
            System.Console.Read();
        }
    }
}

/*
 * Sample Input
abxabcabcaby
abcaby 
*/