Struktur Data Trie (Pokok Awalan)

A Trie, (juga dikenali sebagai awalan pokok) adalah jenis pokok khas yang digunakan untuk menyimpan struktur data bersekutu

Trie (diucapkan percubaan) mendapat namanya dari re trie val - strukturnya menjadikannya algoritma pemadanan bintang.

Konteks

Write your own shuffle method to randomly shuffle characters in a string. 
Use the words text file, located at /usr/share/dict/words, and your shuffle method to create an anagram generator that only produces real words.
Given a string as a command line argument, print one of its anagrams. 

Saya menghadapi cabaran ini minggu ini di Make School's Product Academy.

Kata-kata dalam fail teks dipisahkan oleh baris baru. Pemformatannya menjadikannya lebih mudah untuk memasukkan kata-kata ke dalam struktur data. Buat masa ini, saya menyimpannya dalam senarai - setiap elemen menjadi satu perkataan dari fail.

Salah satu pendekatan untuk cabaran ini adalah:

  • rawak watak-watak dalam rentetan secara rawak
  • kemudian, periksa dengan kata-kata yang terdapat di / usr / share /ict / words untuk mengesahkan bahawa itu adalah perkataan sebenar.

Walau bagaimanapun, pendekatan ini menghendaki saya memeriksa bahawa watak yang diubah secara rawak dalam rentetan baru sepadan dengan salah satu daripada 235,887 perkataan dalam fail itu - itu bermaksud 235,887 operasi untuk setiap rentetan yang ingin saya sahkan sebagai kata sebenar.

Ini adalah penyelesaian yang tidak dapat diterima oleh saya. Saya mula-mula mencari perpustakaan yang telah dilaksanakan untuk memeriksa apakah kata-kata ada dalam bahasa, dan menjumpai pyenchant. Saya pertama kali menyelesaikan cabaran menggunakan perpustakaan, dalam beberapa baris kod.

def generateAnagram(string, language="en_US"): languageDict = enchant.Dict(language) numOfPossibleCombinationsForString = math.factorial(len(string)) for i in range(0, numOfPossibleCombinationsForString): wordWithShuffledCharacters = shuffleCharactersOf(string)
 if languageDict.check(wordWithShuffledCharacters): return wordWithShuffledCharacters return "There is no anagram in %s for %s." % (language, string)

Menggunakan beberapa fungsi perpustakaan dalam kod saya adalah penyelesaian yang cepat dan mudah. Namun, saya tidak banyak belajar dengan mencari perpustakaan untuk menyelesaikan masalah bagi saya.

Saya yakin bahawa perpustakaan tidak menggunakan pendekatan yang saya nyatakan sebelumnya. Saya ingin tahu dan menggali kod sumber - saya menjumpai trie.

Trie

Trie menyimpan data dalam "langkah". Setiap langkah adalah simpul dalam trie.

Menyimpan kata adalah tempat penggunaan yang sempurna untuk jenis pohon ini, kerana terdapat sejumlah huruf yang dapat disatukan untuk membuat tali.

Setiap langkah, atau simpul, dalam bahasa trie akan mewakili satu huruf kata. Langkah-langkah mula bercabang ketika susunan huruf menyimpang dari kata-kata lain di trie, atau ketika kata berakhir.

Saya membuat percubaan direktori di Desktop saya untuk memvisualisasikan turun melalui nod. Ini adalah trie yang mengandungi dua perkataan: epal dan aplikasi.

Perhatikan bahawa akhir kata dilambangkan dengan '$'. Saya menggunakan '$' kerana ia adalah watak unik yang tidak akan hadir dalam sebarang perkataan dalam bahasa apa pun.

Sekiranya saya menambahkan perkataan 'aperture' ke trie ini, saya akan melingkari huruf-huruf dalam perkataan 'aperture' sambil serentak mengundurkan simpul-simpul di trie tersebut. Sekiranya huruf itu wujud sebagai anak dari simpul semasa, turun ke dalamnya. Sekiranya huruf itu tidak wujud sebagai anak dari simpul semasa, buatlah dan kemudian turun ke dalamnya. Untuk menggambarkan langkah-langkah ini menggunakan direktori saya:

Semasa melangkah ke bawah, dua huruf pertama 'aperture' sudah ada di trie, jadi saya turun ke simpul tersebut.

Huruf ketiga, 'e', ​​bagaimanapun, bukan anak dari simpul 'p'. Node baru dibuat untuk mewakili huruf 'e', ​​bercabang dari kata-kata lain dalam trie. Node baru untuk huruf yang diikuti juga dibuat.

Untuk menghasilkan trie dari fail kata, proses ini akan berlaku untuk setiap kata, sehingga semua kombinasi untuk setiap kata disimpan.

Anda mungkin berfikir: "Tunggu, tidak akan memakan waktu lama untuk menghasilkan trie dari fail teks dengan 235,887 kata di dalamnya? Apa gunanya mengulangi setiap watak dalam setiap perkataan? "

Ya, berulang setiap watak setiap perkataan untuk menghasilkan trie memerlukan sedikit masa. Walau bagaimanapun, masa yang diperlukan untuk membuat trie sangat berbaloi - kerana untuk memeriksa sama ada perkataan ada dalam fail teks, memerlukan paling banyak operasi sebanyak panjang perkataan itu sendiri . Jauh lebih baik daripada 235,887 operasi yang akan dilakukan sebelumnya.

Saya menulis versi trie paling mudah, menggunakan kamus bersarang. Ini bukan kaedah yang paling berkesan untuk melaksanakannya, tetapi adalah latihan yang baik untuk memahami logik di sebalik trie.

endOfWord = "$"
def generateTrieFromWordsArray(words): root = {} for word in words: currentDict = root for letter in word: currentDict = currentDict.setdefault(letter, {}) currentDict[endOfWord] = endOfWord return root
def isWordPresentInTrie(trie, word): currentDict = trie for letter in word: if letter in currentDict: currentDict = currentDict[letter] else: return False return endOfWord in currentDict

Anda dapat melihat penyelesaian saya untuk penjana anagram di Github saya. Sejak meneroka algoritma ini, saya memutuskan untuk menjadikan catatan blog ini sebagai salah satu daripada banyak - setiap catatan merangkumi satu algoritma atau struktur data. Kod ini terdapat di repo Algoritma dan Struktur Data - bintangkannya untuk terus dikemas kini!

Langkah seterusnya

Saya cadangkan untuk melihat triwulan Ray Wenderlich. Walaupun ditulis dalam Swift, ia adalah sumber yang berharga untuk penjelasan mengenai pelbagai algoritma.

Mirip dengan trie (tetapi lebih cekap memori) adalah pohon akhiran, atau radix. Ringkasnya, bukannya menyimpan watak tunggal pada setiap simpul, akhir perkataan, akhirannya, disimpan dan jalan dibuat relatif.

Walau bagaimanapun, radix lebih rumit untuk dilaksanakan daripada trie. Saya cadangkan lihat repo radix Ray Wenderlich jika anda berminat.

Ini adalah catatan pertama siri algoritma dan struktur data saya. Di setiap catatan, saya akan mengemukakan masalah yang dapat diselesaikan dengan lebih baik dengan algoritma atau struktur data untuk menggambarkan struktur algoritma / data itu sendiri.

Bintangi repo algoritma saya di Github dan ikuti saya di Twitter jika anda mahu mengikuti!

Adakah anda mendapat nilai dengan membaca artikel ini? Klik di sini untuk berkongsi di Twitter! Sekiranya anda ingin melihat kandungan seperti ini lebih kerap, ikuti saya di Medium dan melanggan buletin sebulan sekali di bawah. Jangan ragu untuk membelikan saya kopi juga.