1. 程式人生 > >Trie樹(字典樹,字首樹,鍵樹)分析詳解

Trie樹(字典樹,字首樹,鍵樹)分析詳解

Trie樹概述

   Trie樹,又稱字典樹、字首樹、單詞查詢樹、鍵樹,是一種多叉樹形結構,是一種雜湊樹的變種。Trie這個術語來自於retrieval,發音為/tri:/ “tree”,也有人讀為/traɪ/ “try”。Trie樹典型應用是用於快速檢索(最長字首匹配),統計,排序和儲存大量的字串,所以經常被搜尋引擎系統用於文字詞頻統計,搜尋提示等場景。它的優點是最大限度地減少無謂的字串比較,查詢效率比較高。

   Trie樹的核心思想是空間換時間,利用字串的公共字首來降低查詢時間的開銷以達到提高效率的目的。

   Trie樹有3個基本性質:

 - 根節點不包含字元,除根節點外每一個節點都只包含一個字元
 - 從根節點到某一節點,路徑上經過的字元連線起來,為該節點對應的字串
 - 每個節點的所有子節點包含的字元都不相同

Trie樹的插入

   上面我們瞭解了Trie樹的性質,現在我們根據Trie樹的性質來建立一個Trie樹。假設我們現在有b,abc,abd,bcd,abcd,efg,hii 這6個單詞,構建出的Trie樹如下圖所示:
這裡寫圖片描述

   搭建Trie的方法很簡單,其實就是將單詞的每個字母逐一插入Trie樹。插入前先看字母對應的節點是否存在,存在則共享該節點,不存在則建立對應的節點。比如要插入新單詞and,就有下面幾步:

 1. 插入第一個字母"a",發現root節點存在子節點a,則共享節點a
 2. 插入第二個字母"n",發現節點a存在子節點n,則共享節點n
 3. 插入第三個字母"d",發現節點n不存在子節點d,則建立子節點d。
 4. 至此,單詞and中所有字母已被插入Trie樹中,然後設定節點d中的標誌位,標記路徑root->a->n->d這條路徑上所有節點的字元可以組成一個單詞and

Trie樹的查詢

   從root節點開始按照單詞的字母順序向下遍歷Trie樹,遍歷完成有兩種情況:

 1. 單詞中每個字母都在Trie樹中被查詢過,此時Trie樹不一定被遍歷完
 2. 單詞中部分字母未在Trie樹中被查詢過,此時Trie樹一定被遍歷完

   查詢單詞是否存在,我們不會管遍歷完成時是上面的哪種情況,我們只需要關注遍歷結束時Trie樹最後一個被遍歷的節點last。若節點last中設定了標誌位(即表示路徑root->…->last上所有節點的字元可以組成一個單詞)則表示被查詢的單詞存在於Trie樹中,否則表示不存在。

演算法思想

   概述中已經說過,Trie的核心思想是空間換時間,利用字串的公共字首來降低查詢時間的開銷以達到提高效率的目的。

   假設字元的種數有m個,有若干個長度為n的字串構成了一個Trie樹,則每個節點的出度為m(即每個節點的可能子節點數量為m),Trie樹的高度為n。很明顯我們浪費了大量的空間來儲存字元,此時Trie樹的最壞空間複雜度為O(m^n)。也正由於每個節點的出度為m,所以我們能夠沿著樹的一個個分支高效的向下逐個字元的查詢,而不是遍歷所有的字串來查詢,此時Trie樹的最壞時間複雜度為O(n)。這正是空間換時間的體現,也是利用公共字首降低查詢時間開銷的體現。

Trie樹的實現

Trie樹和其它資料結構的比較

Trie樹與二叉搜尋樹

   二叉搜尋樹應該是我們最早接觸的樹結構了,我們知道,資料規模為n時,二叉搜尋樹插入、查詢、刪除操作的時間複雜度通常只有O(log n),最壞情況下整棵樹所有的節點都只有一個子節點,退變成一個線性表,此時插入、查詢、刪除操作的時間複雜度是O(n)。

   通常情況下,Trie樹的高度n要遠大於搜尋字串的長度m,故查詢操作的時間複雜度通常為O(m),最壞情況下的時間複雜度才為O(n)。很容易看出,Trie樹最壞情況下的查詢也快過二叉搜尋樹。

   文中Trie樹都是拿字串舉例的,其實它本身對key的適宜性是有嚴格要求的,如果key是浮點數的話,就可能導致整個Trie樹巨長無比,節點可讀性也非常差,這種情況下是不適宜用Trie樹來儲存資料的;而二叉搜尋樹就不存在這個問題。

Trie樹與Hash表

   考慮一下Hash衝突的問題。Hash表通常我們說它的複雜度是O(1),其實嚴格說起來這是接近完美的Hash表的複雜度,另外還需要考慮到hash函式本身需要遍歷搜尋字串,複雜度是O(m)。在不同鍵被對映到“同一個位置”(考慮closed hashing,這“同一個位置”可以由一個普通連結串列來取代)的時候,需要進行查詢的複雜度取決於這“同一個位置”下節點的數目,因此,在最壞情況下,Hash表也是可以成為一張單向連結串列的。

   Trie樹可以比較方便地按照key的字母序來排序(整棵樹先序遍歷一次就好了),這跟絕大多數Hash表是不同的(Hash表一般對於不同的key來說是無序的)。

   在較理想的情況下,Hash表可以以O(1)的速度迅速命中目標,如果這張表非常大,需要放到磁碟上的話,Hash表的查詢訪問在理想情況下只需要一次即可;但是Trie樹訪問磁碟的數目需要等於節點深度。

   很多時候Trie樹比Hash表需要更多的空間,我們考慮這種一個節點存放一個字元的情況的話,在儲存一個字串的時候,沒有辦法把它儲存成一個單獨的塊。Trie樹的節點壓縮可以明顯緩解這個問題,後面會講到。

Trie樹與字尾樹

TODO

Trie樹的改進

  1. 按位Trie樹(Bitwise Trie):原理上和普通Trie樹差不多,只不過普通Trie樹儲存的最小單位是字元,但是Bitwise Trie存放的是位而已。位資料的存取由CPU指令一次直接實現,對於二進位制資料,它理論上要比普通Trie樹快。

  2. 節點壓縮。

    1. 分支壓縮:對於穩定的Trie樹,基本上都是查詢和讀取操作,完全可以把一些分支進行壓縮。例如,前圖中最右側分支的inn可以直接壓縮成一個節點“inn”,而不需要作為一棵常規的子樹存在。Radix樹就是根據這個原理來解決Trie樹過深問題的。

    2. 節點對映表:這種方式也是在Trie樹的節點可能已經幾乎完全確定的情況下采用的,針對Trie樹中節點的每一個狀態,如果狀態總數重複很多的話,通過一個元素為數字的多維陣列(比如Triple Array Trie)來表示,這樣儲存Trie樹本身的空間開銷會小一些,雖說引入了一張額外的對映表。

參考

相關推薦

Trie字典字首分析

Trie樹概述    Trie樹,又稱字典樹、字首樹、單詞查詢樹、鍵樹,是一種多叉樹形結構,是一種雜湊樹的變種。Trie這個術語來自於retrieval,發音為/tri:/ “tree”,也有人讀為/traɪ/ “try”。Trie樹典型應用是用於快速檢索(最

C++中的const成員函式函式聲明後加const或稱常量成員函式用法

在C++的類定義裡面,可以看到類似下面的定義: 01 class List { 02 private: 03 Node * p_he

webstorm工欲善其事必先利其器工具

作者:小蕭ovo 連結:https://zhuanlan.zhihu.com/p/22893295 來源:知乎 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。開發工具webstorm。是在windows環境下的。 xx的方法:安裝完後開啟,第一個介面選擇下面的按鈕,然後就進到下面這個圖

【模板】Trie字典單詞查詢

int n; // 0為根節點 char a[MAX_N]; // a[0] = 0; int p[MAX_N][26]; void Update(string s) { int now = 0, len = s.size(); for(register int i = 0; i < l

Trie字典字首面向物件思想C++實現

Trie樹的功能、思想、實現都寫在程式碼註釋中了 使用: Trie trie = new Trie([TypeCase]); trie. TypeCase= Bit //二進位制 Number // 0-9數字 LowerCase //小寫字母

Trie字典1

stdio.h public ctu 哈希 pac 索引 cas proc ren   Trie樹。又稱字典樹,單詞查找樹或者前綴樹,是一種用於高速檢索的多叉樹結構。   Trie樹與二叉搜索樹不同,鍵不是直接保存在節點中,而是由節點在樹中的位置決定。

trie字典

arc delete png 技術分享 我只 blog 存在 紅色 style 核心思想: 利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的 舉個例子 上圖是由 am as tea too tooth two 構成的字典樹。每個節

Trie tree字典

pri table main radix gcc編譯器 out 字典 name dia   Trie tree有時被稱為(digital tree)或(radix tree or prefix tree)。   可能是編譯器問題,我的實現方法用gcc編譯器,debug沒問

hiho 第2周 Trie字典

oid syn one ++ tac col splay str gif 裸字典樹。AC自動機前綴技能 1 #include <set> 2 #include <map> 3 #include <queue> 4

字典判斷有指定字首的單詞個數

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 500005 int ch[maxn

Trie字典:應用於統計和排序

轉載這篇關於字典樹的原因是看到騰訊面試相關的題:就是在海量資料中找出某一個數,比如2億QQ號中查找出某一個特定的QQ號。。 有人提到字典樹,我就順便了解下字典樹。 [轉自:http://blog.csdn.net/oncealong/article/details

Trie 字典

字典樹(Trie)可以儲存一些 字串->值 的對應關係。 基本上,它跟 Java 的 HashMap 功能相同,都是 key-value 對映,只不過 Trie 的 key 只能是字串。 它的優點是:最大限度地減少無謂的字串比較,查詢效率比雜湊表高。

Trie字典談到字尾

引言 常關注本blog的讀者朋友想必看過此篇文章:從 B樹、B+樹、B*樹談到R 樹 ,這次,咱們來講另外兩種樹:Tire樹與字尾樹。不過,在此之前,先來看兩個問題。 第一個問題: 一個文字檔案,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞,請

Trie字典的C++實現

問題描述: Trie樹 又稱單詞查詢樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計,排序和儲存大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。 舉個例子:os,oh,old,char,chat這些關鍵詞構成的trie樹:          

[ACM] hdu 5147 Sequence II 狀陣列字首字尾和

Sequence II Problem Description Long long ago, there is a sequence A with length n. All numbers in this sequence is no smaller than 1

Trie字典談到字尾10.28修訂

            從Trie樹(字典樹)談到字尾樹說明:本文基本上是“整理”性質,致謝文末的參考文獻。 引言    常關注本blog的讀者朋友想必看過此篇文章:這次,咱們來講另外兩種樹:Tire樹與字尾樹。不過,在此之前,先來看兩個問題。    第一個問題: 一個文字檔

Tire字典資料結構圖解及模板

先在這裡放模板,具體圖解回去再發 #include <map> #include <queue> #include <cstdlib> #include <cm

海量資料處理之Tire字典

第一部分、Trie樹 1.1、什麼是Trie樹     Trie樹,即字典樹,又稱單詞查詢樹或鍵樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計和排序大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。它的優點是:最大限度地減少無謂的字串比較,

數據結構與算法(3)——二叉、二叉搜索

序列化 存在 you 樹遍歷 大於 另一個 分類 出現 遍歷序列 前言:題圖無關,現在開始來學習學習樹相關的知識 前序文章: 數據結構與算法(1)——數組與鏈表(https://www.jianshu.com/p/7b93b3570875) 數據結構與算法(2)——

數據結構 - 紅黑Red Black Tree插入與實現Java

啟示 dpa con 技術分享 節點數 src 通知 一點 this   最終還是決定把紅黑樹的篇章一分為二,插入操作一篇,刪除操作一篇,因為合在一起寫篇幅實在太長了,寫起來都覺得累,何況是閱讀並理解的讀者。       紅黑樹刪除操作請參考 數據結構 - 紅黑樹(Red