字典樹,也稱Trie、字母樹,指的是某個字符串集合對應的形以下圖的有根樹。樹的每條邊上對應有剛好一個字符,每一個頂點表明從根到該節點的路徑所對應的字符串(將全部通過的邊上的字符按順序鏈接起來)。有時咱們也稱Trie上的邊爲轉移,頂點爲狀態。數組
一棵空Trie僅包含一個根節點,該點的字符指針均指向空。spa
當須要插入一個字符串S時,咱們令一個指針P起初指向根節點。而後,依次掃描S中的每一個字符 c : 3d
1.若P的c字符指針指向一個己經存在的節點Q,則令P=Q。指針
2.若P的c字符指針指向空,則新建一個節點Q ,令P的 c 字符指針指向Q,而後令P=Q。 當S中的字符掃描完畢時,在當前節點P上標記它是一個字符串的末尾。code
當須要查詢一個字符串S在Trie中是否存在時,咱們令一個指針P起初指向根節點,而後依次掃描S中的每一個字符c : blog
1.若P的c字符指針指向空,則說明S沒有被插入過Trie ,結束查詢。字符串
2.若P的c字符指針指向一個已經存在的節點Q,則令P=Q 。class
當S中的字符掃描完畢時,若當前節點P被標記爲一個字符串的末尾,則說明S 在 Trie 中存在,不然說明S沒有被插入過Trie。List
在上圖所示的例子中,須要插入和查詢的字符串都由小寫字母構成,因此Trie 的每一個節點具備 26個字符指針,分別爲a到z。上圖展現了在一棵空 Trie中依次插入 " cab " " cos " " car " " cat " " cate"和"rain"後的Trie 的形態,灰色標記了單詞的末尾節點。二進制
能夠看出在Trie 中,字符數據都體如今樹的邊(指針)上,樹的節點僅保存一些額外信息,例如單詞結尾標記等。其空間複雜度是O ( NC ) ,其中 N 是節點個數, C是字符集的大小。
初始化 1.int ch[N][Z]; //Z爲字符集大小
2.bool bo[N]; //若bo=true則表示從根到該點通過的邊上字母組成的字符串是實際字符串集合中的元素
如今要對一個字符集爲小寫英文字母的Trie插入一個字符串S: 1.void insert(char *s) { //char *s表示一個字符數組
2. int len = strlen(s); 3. int u = 1; //1爲根節點
4. for(int i = 0; i < len; ++i){ 5. int c = s[i] - 'a'; 6. if(!ch[u][c]) 7. ch[u][c] = ++tot; //若不存在這條邊則要新建一個節點與轉移邊
8. u = ch[u][c]; //tot爲總點數
9. } 10. bo[u] = true; 11. //在串的結尾處將bo賦值,表示它表明一個實際字符串集合中的元素
12.}
查詢一個字符串S是不是給定字符串集合中某個串的前綴: 1.bool find(char s[]) { 2. int len = strlen(s); 3. int u = 1; 4. for(int i = 0; i < len; ++i){ 5. int c = s[i] - 'a'; 6. if(!ch[u][c]) return false; 7. u = ch[u][c]; 8. } 9. return true; 10.}
【例題1】Phone List(信息學奧賽一本通 1471)
【題目描述】
給定 n 個長度不超過 10 的數字串,問其中是否存在兩個數字串 S,T,使得 S 是 T 的前綴,多組數據。
【輸入】
第一行一個整數 T,表示數據組數。 對於每組數據,第一行一個數 n,接下來 n 行輸入 n 個數字串。
【輸出】
對於每組數據,若存在兩個數字串 S,T,使得 S 是 T 的前綴,則輸出 NO ,不然輸出 YES 。 請注意此處結果與輸出的對應關係!
【輸入樣例】
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
【輸出樣例】
NO
YES
【例題2】The XOR Largest Pair(信息學奧賽一本通 1472)
【題目描述】
在給定的 N 個整數 A1,A2,…, AN 中選出兩個進行異或運算,獲得的結果最大是多少?
【輸入】
第一行一個整數 N。 第二行 N 個整數 Ai。
【輸出】
一個整數表示答案。
【輸入樣例】
5
2 9 5 7 0
【輸出樣例】
14
思路:
對於每一個 i ( 1<=i <= N ) ,咱們但願找到一個 j ( 1 <=j < i ) ,使Ai xor Aj最大。
咱們能夠把每一個整數看做長度爲 32 的二進制 01 串(數值較小時在前邊補 0 ),而且把A1~Ai-1對應的 32 位二進制串插入一棵 Trie 樹(最低二進制位爲葉子節點)。接下來,對於 Ai 對應的 32 位二進制串,咱們在 Trie 中進行一次與查詢相似的過程,每一步都嘗試沿着「與 Ai 的當前位相反的字符指針」向下訪問。若「與 Ai 的當前位相反的字符指針」指向空節點,則只好訪問與 Ai 當前位相同的字符指針。根據 xor 運算「相同得 0 ,不一樣得 1 」的性質,該方法便可找出與 A i作 xor 運算結果最大的Aj。