2011-01-11 11 views
5

Na przykład: Mam tablicaJak ustalić, że jedna tablica jest częścią innej?

var src = new byte[] {1, 2, 3, 4, 5}; 
var tag = new byte[] {3, 4}; 

którzy znają szybki sposób na znalezienie indeks tablicy zawieszki? muszę coś jak następuje:

int FindIndexOfSeq(byte[] src, byte[] sequence); 

sekwencja może mieć więcej niż jeden razy w src.

Rozwiązanie: How to find index of sublist in list?

+1

możliwe powielać http://stackoverflow.com/questions/3529727/how-to-find-index-of-sublist-in-list – nan

+2

To nie jest łatwy do rozwiązania problemem skutecznie. Naiwne, łatwe do zaimplementowania wyszukiwanie to najgorszy przypadek "O (nm)". Możesz to znacznie poprawić (np. Boyer-Moore), ale nie jest to łatwe. http://pl.wikipedia.org/wiki/String_searching_algorithm#Single_pattern_algorithms – Ani

+0

Tylko indeks pierwszego wystąpienia? –

Odpowiedz

1
int FindIndexOfSeq<T>(byte[] src, byte[] tag) 
{ 
    Int32 tagCount = tag.Count();    

    // If `tag` is not empty and `src` contains `tag` 
    if (tagCount > 0 && src.Intersect(tag).Count() == tagCount) 
    { 
     // Find index of first element in `tag` 
     Int32 tagStartIndex = Array.IndexOf(src, tag.First()); 

     // Get the matching slice of `tag` from `src` 
     var newSrc = src.Skip(tagStartIndex).Take(tag.Count()).ToList(); 

     // Zip them together using their difference 
     var sum = Enumerable.Zip(tag, newSrc, (i1, i2) => Convert.ToInt32(i2 - i1)).Sum(); 

     // If total of their differences is zero, both sequences match 
     if (sum == 0) 
     { 
      // return starting index of `tag` in `src` 
      return tagStartIndex; 
     } 
    } 

    // return `Not Found` 
    return -1; 
} 
+0

Czy to nie byłoby złe, jeśli src ma wartość {1, 2, 3, 3, 4, 5}, a tag to {3, 4}? –

2

Oto jedna droga do uzyskania indeksu

for (int i = 0; i < (src.Length - tag.Length); i++) 
{ 
    if (tag.SequenceEqual(src.Skip(i).Take(tag.Length))) 
     Console.WriteLine("It's at position " + i); 
} 

Niestety jest to bardzo powolny.

Jeśli chcesz tylko wiedzieć, czy wszystkie elementy w tag można znaleźć w src (w dowolnej kolejności), a następnie

var src = new byte[] { 1, 2, 3, 4, 5 }; 
var tag = new byte[] { 4, 3 }; 

if (src.Intersect(tag).Count() == tag.Length) 
    Console.WriteLine("tag can be found in src!"); 
+0

Nie, muszę znać indeks, w którym rozpoczyna się sekwencja. –

+0

Wystarczająco inteligentny. +1 – deadlock

+0

Jonas, w twoim przykładzie masz błędną kolejność bajtów w tablicy znaczników. –

2

najlepiej można uzyskać wynosi O (m), ale że ja nieco skomplikowane realizacja. Jeśli spełniasz rozwiązanie, które ma O (m * n) jako najgorszy przypadek, możesz skorzystać z poniższego rozwiązania. Jeśli twoje sekwencje są uporządkowane, a element początkowy w tablicy tag jest obecny tylko raz w src, spowoduje to również O (m).

class Program 
{ 
    static void Main(string[] args) 
    { 
     var src = new byte[] { 1, 2, 3, 4, 5 }; 
     var tag = new byte[] { 3, 4 }; 
     var index = FindIndexOfSeq(src, tag); 
     Console.WriteLine(index); 
     Console.ReadLine(); 
    } 
    static int FindIndexOfSeq<T>(T[] src, T[] seq) 
    { 
     int index = -1; 
     for (int i = 0; i < src.Length - seq.Length + 1; i++) 
     { 
      bool foundSeq = true; 
      for (int j = 0; j < seq.Length; j++) 
      { 
       foundSeq = foundSeq && src[i + j].Equals(seq[j]); 
      } 
      if (foundSeq) 
      { 
       index = i; 
       break; 
      } 
     } 
     return index; 
    } 
} 

Założę, że sekwencja musi być w tej kolejności, a ja skompilowałem ją tylko w firefoxie, więc nie wiem, czy to działa :). Zrobiłem też rodzajowy, więc obsługuje każdy rodzaj tablic nie tylko bajtów.

AKTUALIZACJA: Zaktualizowany kod kompiluje się i działa ... lub mój prosty test zadziałał.

+0

Możesz * poprawić * na 'O (nm)', w rzeczywistości można to zrobić w 'O (n)'. Przykład: Boyer-Moore. http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm – Ani

+0

Masz rację ... Zaktualizowałem tę część i zawarłem prosty program. Ponadto, masz rację z O (n), ale wydaje się, że jest to o wiele bardziej skomplikowany algorytm? Czy na małych zestawach jest szybszy? Myślę, że jest tam mały interes. Jeśli jego sekwencja wygląda tak, jak ta, którą podał, spowoduje to O (n + m). –

+0

Tak, zgadzam się, że wdrożenie któregokolwiek z nich jest prawdopodobnie przesadą w przypadku najczęstszych zastosowań. Ale nadal bym się pozbył "Najlepszą rzeczą, jaką można uzyskać, jest O (m * n)"; to trochę zwodnicze. – Ani

Powiązane problemy