Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wyszukiwarka słów Scrabble:budowanie trie, przechowywanie trie, używanie trie?

Najpierw spójrzmy na ograniczenia problemu. Chcesz przechowywać listę słów dla gry w strukturze danych, która skutecznie obsługuje problem „anagramu”. To znaczy, biorąc pod uwagę „stelaż” składający się z n liter, jakie są wszystkie n lub mniej-literowe słowa z listy słów, które można utworzyć z tego stojaka. lista słów będzie zawierała około 400 000 słów, a więc prawdopodobnie od jednej do dziesięciu megabajtów danych po rozpakowaniu.

Trie to klasyczna struktura danych używana do rozwiązania tego problemu, ponieważ łączy ona zarówno wydajność pamięci, jak i wydajność wyszukiwania. Mając listę słów zawierającą około 400 000 słów o rozsądnej długości, powinieneś być w stanie zachować tę próbę w pamięci. (W przeciwieństwie do rozwiązania typu b-drzewa, w którym większość drzewa jest przechowywana na dysku, ponieważ jest zbyt duże, aby zmieścić się w całej pamięci jednocześnie.)

Trie to w zasadzie nic innego jak drzewo 26-arowe (zakładając, że używasz alfabetu rzymskiego), w którym każdy węzeł ma literę i jeden dodatkowy bit na każdym węźle, który mówi, czy jest to koniec słowa.

Naszkicujmy więc strukturę danych:

class TrieNode
{
    char Letter;
    bool IsEndOfWord;
    List<TrieNode> children; 
}

To oczywiście tylko szkic; prawdopodobnie chciałbyś, aby miały one odpowiednie akcesory i konstruktory właściwości i tak dalej. Może też płaska lista nie jest najlepszą strukturą danych; może jakiś słownik jest lepszy. Radzę najpierw sprawić, by działał, a następnie zmierzyć jego wydajność, a jeśli jest to nie do przyjęcia, poeksperymentować z wprowadzaniem zmian, aby poprawić jego wydajność.

Możesz zacząć od pustej próby:

TrieNode root = new TrieNode('^', false, new List<TrieNode>());

Oznacza to, że jest to „główny” węzeł trie, który reprezentuje początek słowa.

Jak dodać słowo „AA”, pierwsze słowo w słowniku Scrabble? Cóż, najpierw utwórz węzeł dla pierwszej litery:

root.Children.Add('A', false, new List<TrieNode>());

OK, nasza próba jest teraz

^
|
A

Teraz dodaj węzeł dla drugiej litery:

root.Children[0].Children.Add(new trieNode('A', true, new List<TrieNode>()));

Nasza próba jest teraz

^
|
A
|
A$   -- we notate the end of word flag with $

Świetny. Załóżmy teraz, że chcemy dodać AB. Mamy już węzeł dla „A”, więc dodaj do niego węzeł „B$”:

root.Children[0].Children.Add(new trieNode('B', true, new List<TrieNode>());

a teraz mamy

    ^
    |
    A
   / \
  A$   B$

Idź tak dalej. Oczywiście, zamiast pisać „root.Children[0]...”, napiszesz pętlę, która przeszukuje próbkę, aby zobaczyć, czy żądany węzeł istnieje, a jeśli nie, utwórz go.

Aby zapisać twoją wersję na dysku — szczerze, po prostu zapisałbym listę słów jako zwykły plik tekstowy i odbudowałbym wersję, kiedy zajdzie taka potrzeba. Nie powinno to zająć więcej niż 30 sekund, a następnie możesz ponownie użyć próby w pamięci. Jeśli chcesz przechowywać trie w jakimś formacie, który jest bardziej podobny do trie, nie powinno być trudno wymyślić format serializacji.

Aby przeszukać próbę w celu dopasowania stojaka, pomysł polega na zbadaniu każdej części próby, ale przycinanie obszarów, do których stojak nie może pasować. Jeśli nie masz żadnych „A” na stojaku, nie ma potrzeby wchodzenia w żaden węzeł „A”. W poprzednim pytaniu naszkicowałem algorytm wyszukiwania.

Mam implementację trwałej próby w stylu funkcjonalnym, o której chciałem pisać na blogu od jakiegoś czasu, ale nigdy się do tego nie udało. Jeśli w końcu to opublikuję, zaktualizuję to pytanie.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL - SQL_BIG_SELECTS

  2. Instrukcja aktualizacji MySQL do przechowywania pozycji w rankingu

  3. Zwróć wartość logiczną z pliku PHP do pliku AJAX - przycisk Śledź

  4. MySQL Wyszukiwanie pełnotekstowe i SOUNDEX

  5. PDO + MySQL i zepsute kodowanie UTF-8