2013-03-03 4 views
9

Mam następującą sytuację: Mam dużą kolekcję ciągów (powiedzmy 250.000+) o średniej długości może 30 lat. Co muszę zrobić zrobić, to zrobić wiele przeszukiwań w ramach tych .. głównie te będą z StartsWith i Contains rodzaju.jaka jest najszybsza struktura/algorytm zbierania ciągów dla startswith i/lub zawiera wyszukiwania

Kolekcja jest statyczna w czasie wykonywania. Co oznacza, że ​​pierwsze czytanie i wypełnianie wybranego zbioru odbywa się tylko raz. Dlatego wydajność budowania danych nie jest absolutnie ważna. Pamięć również nie stanowi problemu: co oznacza, że ​​nie mam nic przeciwko posiadaniu dwóch kolekcji z tymi samymi danymi w każdym z nich, jeśli jest to potrzebne (np. Dla startwith i innego dla zawiera). Jedyne, co ma znaczenie, to skuteczność wyszukiwań, które powinny zwracać wszystkie elementy pasujące do wyszukiwanego hasła.

Na początku natrafiłem na Trie lub Radix-tree .. ale może są jeszcze lepsze wybory?

Dla zawiera .. Nie mam jeszcze żadnego dobrego pomysłu (poza uruchomieniem kwerendy linq na liście, która nie będzie bardzo szybka z taką ilością danych).

Z góry dziękuję wszystkim!

zmiana: zapomniałem ważną rolę: Zawiera mam na myśli żadnych dokładnych dopasowań w kolekcji .. ale chcę znaleźć wszystkie sznurki w kolekcji zawierających daną searchstring

+0

Czy podciąg dla wyszukiwania zawiera słowo lub pojedyncze znaki? Zastanawiam się, czy zbudowanie indeksu miałoby sens w tym przypadku. –

+0

Powinno obsługiwać znaki. Chociaż ze względu na wydajność mogłem sobie wyobrazić, że przed wyszukiwaniem otrzymam minimalną długość 3 lub więcej znaków. (może myśleć o tym jak autouzupełnianie w polu tekstowym, które wrzuca tylko po wprowadzeniu niektórych znaków) – Mikk

+1

Wyszukaj w internecie hasło "Rabin Karp". To powinno Ci zacząć, ponieważ ma kilka algorytmów wyszukiwania powiązanych ... http: //www.stoimen.com/blog/2012/04/02/algorytmy komputerowe-rabin-karp-string-searching/Pomyśl również o korzystaniu z filtru Blooma i wstępnym ładowaniu go za pomocą łańcuchów podczas uruchamiania. – JimR

Odpowiedz

3

budowania suffix tree pozwoli Ci wykonaj wyszukiwanie podciągu na wszystkich ciągach równolegle w O(1). Pedantyczny we mnie nie może nie zauważyć, że to naprawdę O(n + m), gdzie n to liczba ciągów pasujących do podłańcucha, a m to rozmiar podciąganego podciągu.

Co to jest drzewo przyrostków? W swojej najprostszej implementacji jest to trie z fantazyjną metodą insertowania: oprócz dodawania ciągu dodaje on także każdy możliwy sufiks tego napisu do tria. W tej strukturze danych wyszukiwanie podłańcowe staje się przedrostkowym wyszukiwaniem wszystkich możliwych przyrostków. Ponieważ chcesz także wyszukiwać prefiksy, będziesz chciał dodać znak specjalny przed każdym wstawionym ciągiem i podciągami zapytania. Znak specjalny pozwoli ci rozróżnić sufiks od pełnego łańcucha.

Chociaż ta implementacja drzewa sufiksu jest niezwykle prosta, jest również bardzo nieefektywna (O(n^2) czas i czas kompilacji). Na szczęście istnieją inne, bardziej wydajne implementacje, które mogą znacznie zmniejszyć czas i przestrzeń. Jeden z nich, algorytm Ukkonena, jest bardzo dobrze wyjaśniony w this SO answer i przenosi spację do O(n). Możesz również zajrzeć do suffix arrays, które są równoważne, ale bardziej wydajne reprezentacja drzew sufiksów.

O ile wiem, istnieje wiele znacznie więcej implementacji drzewek przyrostowych (jeden z nich prawdopodobnie trafi w słodkie miejsce na twój przypadek użycia) Po prostu ich nie znam. Zalecam wykonanie pewnych badań na ten temat, zanim zdecydujesz się na wdrożenie.

+0

Nie masz racji co do nieefektywności drzewa sufiksów. Dobra implementacja może poprawić czas O (n) lub O (n log n) i O (n). http://en.wikipedia.org/wiki/Suffix_tree – nhahtdh

+0

to brzmi świetnie do tej pory! szczególnie pomysł ze specjalnym znakiem dla rozróżnienia pomiędzy przyrostkiem i prefiksem! – Mikk

+0

Przeczytam o tym więcej i spróbuję tego na pewno. Czy wystąpi usterka w tablicach przyrostków? Jeśli są bardziej wydajne, prawdopodobnie od razu się na nich skupię. – Mikk