Trie樹結構

以前說搜索提示的時候留了一個尾巴,就是Trie樹的結構沒有說,這一篇簡單的說一下Trie樹的實現方式。golang

1. Trie樹是什麼

在計算機科學中,trie,又稱前綴樹或字典樹,是一種有序樹,用於保存關聯數組,其中的鍵一般是字符串。與二叉查找樹不一樣,鍵不是直接保存在節點中,而是由節點在樹中的位置決定。一個節點的全部子孫都有相同的前綴,也就是這個節點對應的字符串,而根節點對應空字符串。通常狀況下,不是全部的節點都有對應的值,只有葉子節點和部份內部節點所對應的鍵纔有相關的值。算法

Trie這個術語來自於retrieval。根據詞源學,trie的發明者Edward Fredkin把它讀做英語發音:/ˈtriː/ "tree"。可是,其餘做者把它讀做英語發音:/ˈtraɪ/ "try"編程

以上文字來自維基百科數組

2. 應用範圍

搜索提示和分詞是Trie樹的經典應用範圍。微信

3. 基本Trie樹實現

Trie樹又叫字典樹,本質上是一個多叉樹,每個節點就是一個多叉的結構,若是是英文的匹配,那麼是一個26叉樹,每一個節點一個26長度的數組,每一個節點的數據結構以下數據結構

type TrieNode struct{
    flag      bool
    hasNext bool    
    nexts    [26]*TrieNode
}

其中flag保存的是當前節點是否已是一個完整字符串了。hasNext表示是否還有下一節點,而Trie樹畫出來就是下面這個樣子。
圖片描述

從畫出來的圖,很直觀的能夠看出來這棵樹的構造方法和遍歷方法,由於每一個節點都有一個26長度的數組,來了一個字符,經過字符的編號直接就能夠遍歷到下一個節點,查找的時候複雜度就是O(K),K表示查找的字符串長度,這種數據結構簡單明瞭,實現起來也很容易。優化

可是這種數據結構有個問題,就是內存使用得太多了,若是是中文查找的話,須要把全部的中國字都編號到這個數組中,因而有一種優化方法,就是把數組變成變長的,若是按照二分進行每一個節點的查找的話,每一個節點的查找時間變成了O(lg(n)),總體的查找時間變成K*O(log(n)),n是數組平均長度,這樣的話,雖然內存的使用上下降了,可是查找速度變長了,並且插入的時候須要按序插入,插入也變慢了。spa

按照真正的樹形結構,經過各類指針滿天飛的形式來實現Trie樹,基本上屬於新人練手的水平,純粹爲了瞭解這個數據結構或者大學生作作課程設計,工程化的可能性幾乎爲0。設計

4. 雙數組Trie樹

正由於有上面的各類問題,因而有人發明了雙數組Trie樹,其實在這個以前還有個三數組的Trie樹,爲了避免讓你們更迷糊,咱們直接來看看雙數組的形式吧。指針

所謂雙數組Trie樹,固然就是經過兩個數組來實現這棵樹了,這兩個數組分別叫base數組check數組,一個是基礎數組,一個是檢查數組,Suggestion服務對Trie樹的操做基本上須要有Trie樹的構建部分和Trie樹的查詢部分,插入操做基本上不多使用,後面說數據部分的時候會說到爲何。

Trie樹其實是一種有限狀態機,經過狀態轉移矩陣在各個狀態之間跳轉,咱們不去管這兩個概念,會越說越糊塗,若是你實在是有興趣,能夠本身去查查資料,咱們直接來點實在的,用一個例子來看看雙數組Trie樹是如何工做的。

4.0 前提場景

假設咱們的詞庫裏面有這麼一些詞,中國,北京,中華,華北這幾個詞語,須要構建一棵Trie樹,構建好了之後,用戶輸入字的時候,能把中國,中華都給提示出來。這裏的例子直接使用了中文是爲了更直觀,免得都是abc這種例子容易亂,雖然最後的處理上中文有點特殊,但不影響算法描述。

4.1 Trie樹構建

首先,拿到這些個詞之後,第一步就要構建這棵Trie樹了,構建以前,咱們先對每個字進行編號一下,這個只是爲了方便描述,中:1,國:2,北:3,京:4,華:5

初始化

  • 初始化空數組,初始化base和check兩個空數組。

  • base的元素爲1表示是開始位偏移爲1,爲-1表示沒有數據。

  • check的元素中,-1表示沒有數據,-2表示這是一個詞結束了,-3表示是根節點,以下圖所示

圖片描述

初始化好了之後就能夠開始依次讀取數據了,先讀取出中國兩個字,開始插入

插入中國這個詞

插入
  • 從根節點開始,base[0]=1,插入位置爲base[0]+中的編號爲1,因此是base[0]+1=1+1=2,因而獲得應該插入到base[2]的位置。

  • 檢查check[2],看到check[2]爲-1,表示base[2]沒有數據,能夠插入

  • 更新check[2]爲上一個節點的base數組的下標,上一個節點是base[0],因此更新爲0

  • 更新base[2]爲上一個節點的base數組的值,上一個節點base[0]的值是1,因此更新爲1
    按照上面的四個步驟更新完了之後,整個數組變成下面這個樣子,對着圖能夠仔細想一想整個過程,而後你想一想僞代碼是什麼樣子的,再想一想如何編程。

圖片描述

插入
  • 因爲這個詞語還沒結束,因此從base[2]開始繼續往下走

  • 從base[2]開始,插入位置爲base[2]+國的編號是2,因此是base[2]+2=1+2=3,應該插入到base[3]中

  • 檢查check[3],看到check[2]爲-1,表示base[2]沒有數據,能夠插入

  • 更新check[3]爲上一個節點的base數組下標,上一個是base[2],因此更新爲2

  • 更新base[3]爲上一個節點的base數組的值,上一個節點base[2]的值是2,因此更新爲2

圖片描述

插入北京中華這個詞

你們能夠本身插入一下北京中華這兩個詞,插入之後結構變成下面的樣子

圖片描述

插入華北這個詞

到如今一切都很順利,接下來插入華北這個詞,這裏就會遇到衝突了,遇到衝突之後,進行以下算法

插入

這個插入正常,最後圖像以下所示

圖片描述

插入
  • 因爲這個詞語還沒結束,因此從base[6]開始繼續往下走

  • 從base[6]開始,插入位置爲base[2]+北的編號是3,因此是base[6]+3=1+3=4,應該插入到base[4]中

  • 檢查check[4],看到check[2]爲0,表示base[4]有數據,產生衝突!!

  • 從base[6]日後找空閒空閒,空閒空間的概念是兩個數組都是-1

  • 找到base[8]和check[8]爲空閒空間

  • 更新check[8]爲上一節點的值,6

  • 計算base[6]應該的值爲8-北=8-3=5,更新base[6]爲5,解決衝突!!

圖片描述

5. 查詢

要進行查詢,就相對簡單了,拿到一個詞,好比中華,先肯定每一個字的編號,而後按照兩個數組去遍歷,就知道這個詞在不在這個Trie樹中了,複雜度就是詞的長度。

6. 總結

本篇比較簡單,就是上次搜索提示的一個小尾巴,後面會說到分詞的技術,這個Trie樹也是分詞的主要數據結構。


若是你以爲不錯,歡迎轉發給更多人看到,也歡迎關注個人公衆號,主要聊聊搜索,推薦,廣告技術,還有瞎扯。。文章會在這裏首先發出來:)掃描或者搜索微信號XJJ267或者搜索西加加語言就行
圖片描述

相關文章
相關標籤/搜索