日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

字典树(Trie)

發(fā)布時(shí)間:2024/10/5 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字典树(Trie) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、定義

Trie樹,又稱為前綴樹(Prefix Tree)、單詞查找樹或鍵樹,是一種多叉樹結(jié)構(gòu)。

二、基本性質(zhì)

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

三、代碼

#include <iostream>#include <string>using namespace std;#define ALPHABET_SIZE 26typedef struct trie_node {int count; // 記錄該節(jié)點(diǎn)代表的單詞的個(gè)數(shù)trie_node *children[ALPHABET_SIZE]; // 各個(gè)子節(jié)點(diǎn) }*trie;trie_node* create_trie_node() {trie_node* pNode = new trie_node();pNode->count = 0;for(int i=0; i<ALPHABET_SIZE; ++i)pNode->children[i] = NULL;return pNode; }void trie_insert(trie root, char* key) {trie_node* node = root;char* p = key;while(*p){if(node->children[*p-'a'] == NULL){node->children[*p-'a'] = create_trie_node();}node = node->children[*p-'a'];++p;}node->count += 1; }/*** 查詢:不存在返回0,存在返回出現(xiàn)的次數(shù)*/ int trie_search(trie root, char* key) {trie_node* node = root;char* p = key;while(*p && node!=NULL){node = node->children[*p-'a'];++p;}if(node == NULL)return 0;elsereturn node->count; }int main() {// 關(guān)鍵字集合char keys[][8] = {"the", "a", "there", "answer", "any", "by", "bye", "their"};trie root = create_trie_node();// 創(chuàng)建trie樹for(int i = 0; i < 8; i++)trie_insert(root, keys[i]);// 檢索字符串char s[][32] = {"Present in trie", "Not present in trie"};printf("%s --- %s\n", "the", trie_search(root, "the")>0?s[0]:s[1]);printf("%s --- %s\n", "these", trie_search(root, "these")>0?s[0]:s[1]);printf("%s --- %s\n", "their", trie_search(root, "their")>0?s[0]:s[1]);printf("%s --- %s\n", "thaw", trie_search(root, "thaw")>0?s[0]:s[1]);return 0; }

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

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

1、插入和查詢的效率很高,均是O(m),其中 m 是待插入/查詢的 字符串長(zhǎng)度 。

2、關(guān)于查詢,有人會(huì)說(shuō)hash表時(shí)間復(fù)雜度是O(1)不是更快?但是哈希搜索的效率取決于哈希函數(shù)的好壞,若一個(gè)壞的hash函數(shù)導(dǎo)致了很多沖突,效率不一定比Trie樹高。

3、Trie樹中不同的關(guān)鍵字不會(huì)產(chǎn)生沖突。

4、Trie樹中只有在允許一個(gè)關(guān)鍵字關(guān)聯(lián)多個(gè)值的情況下才有類似hash碰撞發(fā)生。

5、Trie樹不用求hash值,對(duì)短字符串有更快的速度。通常,求hash值也是需要遍歷字符串的(與hash函數(shù)相關(guān))。

Trie樹可以對(duì)關(guān)鍵字 按照字典序排序 (先序遍歷)。

字典排序(lexicographical order)是一種對(duì)于隨機(jī)變量形成序列的排序方法。其方法是,按照字母順序,或者數(shù)字小大順序,由小到大的形成序列。

6、每一顆Trie樹都可以被看做一個(gè)簡(jiǎn)單版的確定有限狀態(tài)的自動(dòng)機(jī)(DFA,deterministic finite automation),也就是說(shuō),對(duì)于一個(gè)任意給定屬于該自動(dòng)機(jī)的狀態(tài)(①)和一個(gè)屬于該自動(dòng)機(jī)字母表的字符(②),都可以根據(jù)給定的轉(zhuǎn)移函數(shù)(③)轉(zhuǎn)到下一個(gè)狀態(tài)。其中:

① 對(duì)于Trie樹的每一個(gè)節(jié)點(diǎn)都確定一個(gè)自動(dòng)機(jī)的狀態(tài)。

② 給定一個(gè)屬于該自動(dòng)機(jī)字母表的字符,在圖中可以看到根據(jù)不同字符形成的分支;

③ 從當(dāng)前節(jié)點(diǎn)進(jìn)入下一層次節(jié)點(diǎn)的過(guò)程進(jìn)過(guò)狀態(tài)轉(zhuǎn)移函數(shù)得出。
核心思想是:空間換時(shí)間,利用字符串的公共前綴來(lái)減少無(wú)謂的字符串比較以達(dá)到提高查詢效率的目的。

缺點(diǎn)

當(dāng)hash函數(shù)很好時(shí),Trie樹的查找效率低于哈希搜索。

空間消耗大。

五、應(yīng)用

1、字符串檢索

檢索、查詢功能是Trie樹最原始功能,思路就是從根節(jié)點(diǎn)開始一個(gè)一個(gè)字符進(jìn)行比較。

如果沿路比較,發(fā)現(xiàn)不同的字符,則表示該字符串在集合中不存在。

如果所有的字符全部比較并且完全相同,還需要判斷最后一個(gè)節(jié)點(diǎn)標(biāo)識(shí)位(標(biāo)記該節(jié)點(diǎn)是否為一個(gè)關(guān)鍵字)。

2、詞頻統(tǒng)計(jì)?

Trie樹常被搜索引擎用于文本詞頻統(tǒng)計(jì)。

思路:為了實(shí)現(xiàn)詞頻統(tǒng)計(jì),我們修改了節(jié)點(diǎn)結(jié)構(gòu),用一個(gè)整型變量count來(lái)計(jì)數(shù)。對(duì)每一個(gè)關(guān)鍵字執(zhí)行插入操作,若已存在,計(jì)數(shù)加1,若不存在,插入后count置 1。?
(1. 2. 都可以用hash table做)

3、字符串排序?

Trie樹可以對(duì)大量字符串按字典序進(jìn)行排序,思路也很簡(jiǎn)單:遍歷一次所有關(guān)鍵字,將它們?nèi)坎迦雝rie樹,樹的每個(gè)結(jié)點(diǎn)的所有兒子很顯然地按照字母表排序,然后先序遍歷輸出Trie樹中所有關(guān)鍵字即可。

4、前綴匹配?

例如:找出一個(gè)字符串集合中所有以ab開頭的字符串。我們只需要用所有字符串構(gòu)造一個(gè)trie樹,然后輸出以a->b->開頭的路徑上的關(guān)鍵字即可。 trie樹前綴匹配常用于搜索提示。如當(dāng)輸入一個(gè)網(wǎng)址,可以自動(dòng)搜索出可能的選擇。當(dāng)沒(méi)有完全匹配的搜索結(jié)果,可以返回前綴最相似的可能。

5、作為輔助結(jié)構(gòu)?

如后綴樹,AC自動(dòng)機(jī)?
有窮自動(dòng)機(jī) 參考資料:http://blog.csdn.net/yukuninfoaxiom/article/details/6057736

6、與哈希表相比?

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

  • trie數(shù)據(jù)查找與不完美哈希表(鏈表實(shí)現(xiàn))在最壞情況下更快;對(duì)于trie樹,最差為O(m),m為查找字符串的長(zhǎng)度;對(duì)于不完美哈希表,會(huì)有鍵值沖突(不同鍵哈希相同),最壞為O(N),N為全部字符產(chǎn)生的個(gè)數(shù)。典型情況是O(m)用于哈希計(jì)算,O(1)用于數(shù)據(jù)查找。
  • trie中不同鍵沒(méi)有沖突
  • trie的桶與哈希表用于存儲(chǔ)鍵沖突的桶類似,僅在單個(gè)鍵與多個(gè)值關(guān)聯(lián)時(shí)需要
  • 當(dāng)更多的鍵加入到trie中,無(wú)需提供hash方法或改變hash方法
  • trie通過(guò)鍵為條目提供字母順序?
  • 缺點(diǎn):

  • trie數(shù)據(jù)查找在某些情況下(磁盤或隨機(jī)訪問(wèn)時(shí)間遠(yuǎn)遠(yuǎn)高于主存)比哈希表慢
  • 當(dāng)鍵值為某些類型(如浮點(diǎn)型),前綴鏈很長(zhǎng)且前綴不是特別有意義。
  • 一些trie會(huì)比hash表更消耗內(nèi)存。對(duì)于trie,每個(gè)字符串的每個(gè)字符都要分配內(nèi)存;對(duì)于大多數(shù)hash,只需要為整個(gè)條目分配一塊內(nèi)存。
  • 7、與二叉搜索樹相比

    二叉搜索樹,又稱二叉排序樹,它滿足:

  • 任意節(jié)點(diǎn)如果左子樹不為空,左子樹所有節(jié)點(diǎn)的值都小于根節(jié)點(diǎn)的值;
  • 任意節(jié)點(diǎn)如果右子樹不為空,右子樹所有節(jié)點(diǎn)的值都大于根節(jié)點(diǎn)的值;
  • 左右子樹也都是二叉搜索樹;
  • 所有節(jié)點(diǎn)的值都不相同。
  • 其實(shí)二叉搜索樹的優(yōu)勢(shì)已經(jīng)在與查找、插入的時(shí)間復(fù)雜度上了,通常只有O(log n),很多集合都是通過(guò)它來(lái)實(shí)現(xiàn)的。在進(jìn)行插入的時(shí)候,實(shí)質(zhì)上是給樹添加新的葉子節(jié)點(diǎn),避免了節(jié)點(diǎn)移動(dòng),搜索、插入和刪除的復(fù)雜度等于樹的高度,屬于O(log n),最壞情況下整棵樹所有的節(jié)點(diǎn)都只有一個(gè)子節(jié)點(diǎn),完全變成一個(gè)線性表,復(fù)雜度是O(n)。

    Trie樹在最壞情況下查找要快過(guò)二叉搜索樹,如果搜索字符串長(zhǎng)度用m來(lái)表示的話,它只有O(m),通常情況(樹的節(jié)點(diǎn)個(gè)數(shù)要遠(yuǎn)大于搜索字符串的長(zhǎng)度)下要遠(yuǎn)小于O(n)。
    ?

    六、改進(jìn)

    1、按位樹(Btiwise Trie):原理上和普通Trie樹差不多,只不過(guò)普通Trie樹存儲(chǔ)的最小單位是字符,但是Bitwise Trie存放的是位而已。位數(shù)據(jù)的存取由CPU指令一次直接實(shí)現(xiàn),對(duì)于二進(jìn)制數(shù)據(jù),它理論上要比普通Trie樹快。

    2、節(jié)點(diǎn)壓縮

    ①分支壓縮: 對(duì)于穩(wěn)定的Trie樹,基本上都是查找和讀取的操作,完全可以把一些分支進(jìn)行壓縮。例如,下圖中最右側(cè)分支inn可以直接壓縮成一個(gè)節(jié)點(diǎn)“inn”,而不需要作為一個(gè)常規(guī)子樹存在。Radix樹就是根據(jù)這個(gè)原理來(lái)解決Trie樹過(guò)深的問(wèn)題。?

    ②節(jié)點(diǎn)映射表:這種方式也是Trie樹節(jié)點(diǎn)可能幾乎完全確定下采用的,針對(duì)Trie樹節(jié)點(diǎn)的每一個(gè)狀態(tài),如果狀態(tài)總數(shù)重復(fù)很多的話,通過(guò)一個(gè)元素為數(shù)字的多維數(shù)組(比如Triple Array Trie)來(lái)表示,這樣存儲(chǔ)Trie樹本身的空間開銷會(huì)小一些,雖然引入了額外的映射表。

    3、雙數(shù)組TRIE樹(Double Array Trie)

    它在保證Trie樹檢索速度的前提下,提高空間利用率而提出的一種數(shù)據(jù)結(jié)構(gòu),本質(zhì)上還是一個(gè)確定有限自動(dòng)機(jī)。(所謂DFA就是一個(gè)能夠?qū)崿F(xiàn)狀態(tài)專一的自動(dòng)機(jī),對(duì)于一個(gè)給定的屬于該自動(dòng)機(jī)的狀態(tài)和一個(gè)數(shù)據(jù)該自動(dòng)機(jī)字符表Σ的字符,它能夠根據(jù)預(yù)先給定的狀態(tài)轉(zhuǎn)移函數(shù)轉(zhuǎn)移到下一個(gè)狀態(tài)。)

    對(duì)于DAT來(lái)說(shuō),每個(gè)節(jié)點(diǎn)代表自動(dòng)機(jī)的一個(gè)狀態(tài), 根據(jù)變量的不同,進(jìn)行狀態(tài)轉(zhuǎn)移,當(dāng)達(dá)到結(jié)束狀態(tài)或者無(wú)法轉(zhuǎn)移時(shí),完成查詢。

    參考資料:http://blog.csdn.net/zzran/article/details/8462002

    七、例題

    http://acm.hdu.edu.cn/showproblem.php?pid=1251

    http://acm.hdu.edu.cn/showproblem.php?pid=1671

    八、參考文章

    https://blog.csdn.net/hihozoo/article/details/51248823

    http://www.raychase.net/1783?replytocom=264917

    https://blog.csdn.net/v_july_v/article/details/6897097

    http://www.cnblogs.com/tanky_woo/archive/2010/09/24/1833717.html

    總結(jié)

    以上是生活随笔為你收集整理的字典树(Trie)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。