用其他子数组替换所有子数组的高效算法

时间:2017-01-02 23:25:33

标签: c# algorithm search replaceall

我有一个字节数组(可以变得非常大,超过3200万字节),我需要用相同长度的其他子数组替换一些子数组。 我当前的方法是在字节数组中搜索我需要替换的所有子数组,每次我找到一个将子数组的索引添加到列表中,然后继续。

我的代码如下。我有一种唠叨的感觉,这不能有效,因为3200万字节需要超过10秒才能完成搜索和替换。我传递8个字符串来替换,所以它基本上最终搜索16个子数组。
任何人都会看到我的算法存在任何缺陷或更有效的缺陷吗?


附:我实际上并没有在这段代码中替换它们,只是找到索引。我的代码应该非常有效。

 public class Search
{
    public List<int> positions;
    public List<int> lengths;
    private List<byte[]> stringsToSearchFor;
    public Search(List<string> strings){
        stringsToSearchFor = new List<byte[]>();
        positions = new List<int>();
        lengths = new List<int>();
        foreach (string tempString in strings){
            stringsToSearchFor.Add(Encoding.ASCII.GetBytes(tempString));
            stringsToSearchFor.Add(Encoding.Unicode.GetBytes(tempString));
        }
    }

    public void SearchBytes(byte[] haystack){
        int[] arrayOfInt = new int[stringsToSearchFor.Count];
        bool[] arrayOfBoolean = new bool[stringsToSearchFor.Count];
        for (var i = 0; i < haystack.Length; i++){
            byte currentByte = haystack[i];
            for (int stringCounter = 0; stringCounter < arrayOfBoolean.Length; stringCounter++)
            {
                byte[] stringLookFor = stringsToSearchFor.ElementAt(stringCounter);
                byte currentStringByte = stringLookFor[arrayOfInt[stringCounter]];
                //Saying the current byte is the desired one
                if (currentStringByte == currentByte)
                {
                    if (arrayOfInt[stringCounter] + 1 == stringLookFor.Length){
                        positions.Add(i - stringLookFor.Length + 1);
                        lengths.Add(stringLookFor.Length);
                        arrayOfInt[stringCounter] = 0;
                    }
                    else
                    {
                        arrayOfInt[stringCounter]++;
                    }
                }
                else
                {
                    arrayOfInt[stringCounter] = 0;
                }
            }
        }
        return;
    }



}

2 个答案:

答案 0 :(得分:3)

我可以看出SearchBytes()只有2个嵌套for循环,这个暴力搜索算法有一个bug。这种蛮力搜索需要3个嵌套循环:对于每个针脚中的每个起始位置,对于每个针线,您需要一个循环来检查整个针是否出现在大海捞针中的那个位置。 (如果发现字符不匹配,这个最里面的循环可能会提前中止。)

这是一个具体的例子:如果干草堆是ABCABCABD并且你的一根针串是ABCABD,那么这个字符串将无法找到,尽管它确实发生了。那是因为一旦你的算法看到大海捞针中的第二个C,它就会得出结论,它必须从大海捞针中的当前位置开始寻找针头,而实际上它需要从较早的位置开始寻找。

无论如何,用于在长度为n的草堆中搜索单个长度为m的针串的蛮力的时间复杂度为O(nm),如果两者都是中等长度则非常可怕。 John Kurlak suggested Knuth-Morris-Pratt or Rabin-Karp,如果你正在寻找一些大的字符串,那么运行其中任何一个肯定会加快速度(以及正确 :-P),但是有效地专门针对的算法在字符串中查找多个字符串称为Aho-Corasick algorithm。需要时间O(n + s + k),其中n是干草堆大小,s是要搜索的针串大小的总和,k是任何针串的出现次数 - 这是很漂亮的很难被击败。

答案 1 :(得分:2)

你基本上是在进行暴力搜索。你可以做更类似于Knuth-Morris-PrattRabin-Karp字符串搜索算法的事情(而不是在字符串中搜索字符序列,而是在数组中搜索字节序列),而不是做蛮力。