<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【NLP】一種好用的樹結(jié)構(gòu):Trie樹

          共 5442字,需瀏覽 11分鐘

           ·

          2022-05-11 05:23

          1

          Trie樹簡介

          在計(jì)算機(jī)科學(xué)中,trie,又稱前綴樹或字典樹,是一種有序樹,用于保存關(guān)聯(lián)數(shù)組,其中的鍵通常是字符串。與二叉查找樹不同,鍵不是直接保存在節(jié)點(diǎn)中,而是由節(jié)點(diǎn)在樹中的位置決定。一個(gè)節(jié)點(diǎn)的所有子孫都有相同的前綴,也就是這個(gè)節(jié)點(diǎn)對(duì)應(yīng)的字符串,而根節(jié)點(diǎn)對(duì)應(yīng)空字符串。一般情況下,不是所有的節(jié)點(diǎn)都有對(duì)應(yīng)的值,只有葉子節(jié)點(diǎn)和部分內(nèi)部節(jié)點(diǎn)所對(duì)應(yīng)的鍵才有相關(guān)的值。

          Trie這個(gè)術(shù)語來自于retrieval。根據(jù)詞源學(xué),trie的發(fā)明者Edward Fredkin把它讀作/?tri?/ "tree"。但是,其他作者把它讀作/?tra?/ "try"。

          在圖示中,鍵標(biāo)注在節(jié)點(diǎn)中,值標(biāo)注在節(jié)點(diǎn)之下。每一個(gè)完整的英文單詞對(duì)應(yīng)一個(gè)特定的整數(shù)。Trie可以看作是一個(gè)確定有限狀態(tài)自動(dòng)機(jī),盡管邊上的符號(hào)一般是隱含在分支的順序中的。Eg.一個(gè)保存了8個(gè)單詞的字典樹的結(jié)構(gòu)如下圖所示,8個(gè)單詞分別是:“A”,“to”,“tea”,“ted”,“ten”,“i” ,“in”,“inn”。

          另外,單詞查找樹,Trie樹,是一種樹形結(jié)構(gòu),是一種哈希樹的變種。典型應(yīng)用是用于統(tǒng)計(jì),排序和保存大量的字符串(但不僅限于字符串),所以經(jīng)常被搜索引擎系統(tǒng)用于文本詞頻統(tǒng)計(jì)。它的優(yōu)點(diǎn)是:利用字符串的公共前綴來減少查詢時(shí)間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。

          2

          Trie樹性質(zhì)

          它有3個(gè)基本性質(zhì):

          • 根節(jié)點(diǎn)不包含字符,除根節(jié)點(diǎn)外每一個(gè)節(jié)點(diǎn)都只包含一個(gè)字符;
          • 從根節(jié)點(diǎn)到某一節(jié)點(diǎn),路徑上經(jīng)過的字符連接起來,為該節(jié)點(diǎn)對(duì)應(yīng)的字符串;
          • 每個(gè)節(jié)點(diǎn)的所有子節(jié)點(diǎn)包含的字符都不相同。

          3

          基本操作

          其基本操作有:查找、插入和刪除,當(dāng)然刪除操作比較少見。

          4

          實(shí)現(xiàn)方法

          搜索字典項(xiàng)目的方法為:

          • (1)從根結(jié)點(diǎn)開始一次搜索;
          • (2) 取得要查找關(guān)鍵詞的第一個(gè)字母,并根據(jù)該字母選擇對(duì)應(yīng)的子樹并轉(zhuǎn)到該子樹繼續(xù)進(jìn)行檢索;
          • (3) 在相應(yīng)的子樹上,取得要查找關(guān)鍵詞的第二個(gè)字母,并進(jìn)一步選擇對(duì)應(yīng)的子樹進(jìn)行檢索。
          • (4) 迭代過程……
          • (5) 在某個(gè)結(jié)點(diǎn)處,關(guān)鍵詞的所有字母已被取出,則讀取附在該結(jié)點(diǎn)上的信息,即完成查找。其他操作類似處理

          5

          實(shí)現(xiàn) Trie (前綴樹)

          關(guān)于Trie樹實(shí)現(xiàn),可以移步看下LeetCode208. 實(shí)現(xiàn) Trie (前綴樹)

          輸入
          ["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
          [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
          輸出
          [null, null, true, false, true, null, true]

          解釋
          Trie trie = new Trie();
          trie.insert("apple");
          trie.search("apple"); ? // 返回 True
          trie.search("app"); ? ? // 返回 False
          trie.startsWith("app"); // 返回 True
          trie.insert("app");
          trie.search("app"); ? ? // 返回 True

          來源:力扣(LeetCode)
          鏈接:https://leetcode-cn.com/problems/implement-trie-prefix-tree

          具體實(shí)現(xiàn)如下:

          class TrieNode(object):
          ? ?def __init__(self):
          ? ? ? ?"""
          ? ? ? ?Initialize your data structure here.
          ? ? ? ?"""
          ? ? ? ?self.data = {}
          ? ? ? ?self.is_word = False


          class Trie:
          ? ?def __init__(self):
          ? ? ? ?"""
          ? ? ? ?Initialize your data structure here.
          ? ? ? ?"""
          ? ? ? ?self.root = TrieNode()

          ? ?def insert(self, word):
          ? ? ? ?"""
          ? ? ? ?Inserts a word into the trie.
          ? ? ? ?:type word: str
          ? ? ? ?:rtype: void
          ? ? ? ?"""
          ? ? ? ?node = self.root
          ? ? ? ?for chars in word:
          ? ? ? ? ? ?child = node.data.get(chars)
          ? ? ? ? ? ?if not child:
          ? ? ? ? ? ? ? ?node.data[chars] = TrieNode()
          ? ? ? ? ? ?node = node.data[chars]
          ? ? ? ?node.is_word = True

          ? ?def search(self, word):
          ? ? ? ?"""
          ? ? ? ?Returns if the word is in the trie.
          ? ? ? ?:type word: str
          ? ? ? ?:rtype: bool
          ? ? ? ?"""
          ? ? ? ?node = self.root
          ? ? ? ?for chars in word:
          ? ? ? ? ? ?node = node.data.get(chars)
          ? ? ? ? ? ?if not node:
          ? ? ? ? ? ? ? ?return False
          ? ? ? ?return node.is_word ?# 判斷單詞是否是完整的存在在trie樹中

          ? ?def startsWith(self, prefix):
          ? ? ? ?"""
          ? ? ? ?Returns if there is any word in the trie that starts with the given prefix.
          ? ? ? ?:type prefix: str
          ? ? ? ?:rtype: bool
          ? ? ? ?"""
          ? ? ? ?node = self.root
          ? ? ? ?for chars in prefix:
          ? ? ? ? ? ?node = node.data.get(chars)
          ? ? ? ? ? ?if not node:
          ? ? ? ? ? ? ? ?return False
          ? ? ? ?return True

          ? ?def get_start(self, prefix):
          ? ? ? ?"""
          ? ? ? ? ?Returns words started with prefix
          ? ? ? ? ?返回以prefix開頭的所有words
          ? ? ? ? ?如果prefix是一個(gè)word,那么直接返回該prefix
          ? ? ? ? ?:param prefix:
          ? ? ? ? ?:return: words (list)
          ? ? ? ?"""

          ? ? ? ?def get_key(pre, pre_node):
          ? ? ? ? ? ?word_list = []
          ? ? ? ? ? ?if pre_node.is_word:
          ? ? ? ? ? ? ? ?word_list.append(pre)
          ? ? ? ? ? ?for x in pre_node.data.keys():
          ? ? ? ? ? ? ? ?word_list.extend(get_key(pre + str(x), pre_node.data.get(x)))
          ? ? ? ? ? ?return word_list

          ? ? ? ?words = []
          ? ? ? ?if not self.startsWith(prefix):
          ? ? ? ? ? ?return words
          ? ? ? ?if self.search(prefix):
          ? ? ? ? ? ?words.append(prefix)
          ? ? ? ? ? ?return words
          ? ? ? ?node = self.root
          ? ? ? ?for chars in prefix:
          ? ? ? ? ? ?node = node.data.get(chars)
          ? ? ? ?return get_key(prefix, node)


          if __name__ == '__main__':
          ? ?trie = Trie()

          ? ?print('trie.insert("apple"):', trie.insert("apple"))
          ? ?print('trie.insert("appal"):', trie.insert("appal"))
          ? ?print('trie.insert("appear"):', trie.insert("appear"))
          ? ?print('trie.insert("apply"):', trie.insert("apply"))
          ? ?print('trie.insert("appulse"):', trie.insert("appulse"))

          ? ?print('trie.search("apple"):', trie.search("apple")) ?# 返回 True
          ? ?print('trie.search("app"):', trie.search("app")) ?# 返回 False

          ? ?print('trie.startsWith("app"):', trie.startsWith("app")) ?# 返回 True
          ? ?print('trie.insert("app"):', trie.insert("app"))
          ? ?print('trie.search("app"):', trie.search("app"))

          ? ?print('trie.search("app"):', trie.get_start("app"))
          ? ?print('trie.search("ap"):', trie.get_start('ap'))

          結(jié)果輸出如下:

          F:\ProgramData\Anaconda3\python.exe F:/Projects/nlp-trie/main.py
          trie.insert("apple"): None
          trie.insert("appal"): None
          trie.insert("appear"): None
          trie.insert("apply"): None
          trie.insert("appulse"): None
          trie.search("apple"): True
          trie.search("app"): False
          trie.startsWith("app"): True
          trie.insert("app"): None
          trie.search("app"): True
          trie.search("app"): ['app']
          trie.search("ap"): ['app', 'apple', 'apply', 'appal', 'appear', 'appulse']

          Process finished with exit code 0

          6

          應(yīng)用

          • 輸入框提示/自動(dòng)補(bǔ)全:trie 常用于搜索提示。如當(dāng)輸入一個(gè)網(wǎng)址,可以自動(dòng)搜索出可能的選擇。當(dāng)沒有完全匹配的搜索結(jié)果,可以返回前綴最相似的可能。
          • 字符串檢索、模糊匹配
          • 文本預(yù)測(cè)、自動(dòng)完成,see also,拼寫檢查
          • 在NLP中的應(yīng)用,主要有基于字典樹的文本分詞、短語提取、實(shí)體提取等

          7

          優(yōu)缺點(diǎn)

          優(yōu)點(diǎn):

          可以最大限度地減少無謂的字符串比較,故可以用于詞頻統(tǒng)計(jì)和大量字符串排序。跟哈希表比較:

          1. 最壞情況時(shí)間復(fù)雜度比hash表好

          2. 沒有沖突,除非一個(gè)key對(duì)應(yīng)多個(gè)值(除key外的其他信息)

          3. 自帶排序功能(類似Radix Sort),中序遍歷trie可以得到排序。

          缺點(diǎn):

          1. 雖然不同單詞共享前綴,但其實(shí)trie是一個(gè)以空間換時(shí)間的算法。其每一個(gè)字符都可能包含至多字符集大小數(shù)目的指針。

          2. 如果數(shù)據(jù)存儲(chǔ)在外部存儲(chǔ)器等較慢位置,Trie會(huì)較hash速度慢(hash訪問O(1)次外存,Trie訪問O(樹高))。

          3. 長的浮點(diǎn)數(shù)等會(huì)讓鏈變得很長??捎胋itwise trie改進(jìn)。

          8

          時(shí)間復(fù)雜度

          時(shí)間復(fù)雜度:創(chuàng)建時(shí)間復(fù)雜度為O(L),查詢時(shí)間復(fù)雜度是O(logL),查詢時(shí)間復(fù)雜度最壞情況下是O(L),L是字符串的長度。

          9

          參考資料

          • 字典樹 百度百科
          • Trie wikipedia
          • Trie Python實(shí)現(xiàn)
          • Trie樹學(xué)習(xí)及python實(shí)現(xiàn)
          • python 實(shí)現(xiàn) trie(字典) 樹
          • Trie樹(字典樹)詳細(xì)知識(shí)點(diǎn)及其應(yīng)用



          往期精彩回顧




          瀏覽 48
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲天堂一区二区三区在线观看 | ThePorn精品无码 | 亚洲精品夜色 | 精品国产一区二区三区久久久狼,91精品一 | 中文字幕AV在线播放 |