分類: algorithm
2013-09-13 00:02
313人閱讀收藏
舉報trie樹
trie樹
,又稱單詞查詢樹或鍵樹
,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計和排序大量的字串(但不僅限於字串),
所以經常被搜尋引擎系統用於文字詞頻統計,還可以用來求單詞的字首
。它的優點是:最大限度地減少無謂的字串比較,查詢效率比雜湊表高。
本文討論一棵最簡單的trie樹,基於英文26個字母組成的字串,討論插入字串、判斷字首是否存在、查詢字串等基本操作;至於trie樹的刪除單個節點實在是少見,故在此不做詳解。
ltrie
原理trie
的核心思想是空間換時間。利用字串的公共字首來降低查詢時間的開銷以達到提高效率的目的。
ltrie
性質好多人說trie的根節點不包含任何字元資訊,我所習慣的trie根節點卻是包含資訊的,而且認為這樣也方便,下面說一下它的性質 (基於本文所討論的簡單trie樹)
1.字元的種數決定每個節點的出度,即branch陣列(空間換時間思想)
2.branch
陣列的下標代表字元相對於a的相對位置
3.採用標記的方法確定是否為字串。
4.插入、查詢的複雜度均為o(len),len為字串長度
ltrie
的示意圖
如圖所示,該trie樹存有abc、d、da、dda四個字串,如果是字串會在節點的尾部進行標記。沒有後續字元的branch分支指向null
我有個小小的疑問如果按照:
struct trie
那我們將da,dc插入到trie樹,雖然們標記了第二層的節點flag,我們是不是就無法區分,到底是da還是dc呢。後來在床上想了一下,其實應該是這樣的。da插入到trie樹裡面,其實有三層,第一層的d-》乙個節點,這個節點a—》指向乙個空節點(flag被標記),從事上面的圖也可以看出來。上圖中插入abc,c節點指向乙個被標記的空節點。
ltrie
trie
的優點舉例
已知n個由小寫字母構成的平均長度為10的單詞,判斷其中是否存在某個串為另乙個串的字首子串。下面對比3種方法:
1.最容易想到的:即從字串集中從頭往後搜,看每個字串是否為字串集中某個字串的字首,複雜度為o(n^2)。
2.使用hash:我們用hash存下所有字串的所有的字首子串。建立存有子串hash的複雜度為o(n*len)。查詢的複雜度為o(n)* o(1)= o(n)。
3.使用trie:因為當查詢如字串abc是否為某個字串的字首時,顯然以b,c,d....等不是以a開頭的字串就不用查詢了。所以建立trie的複雜度為o(n*len),而建立+查詢在trie中是可以同時執行的,建立的過程也就可以成為查詢的過程,hash就不能實現這個功能。所以總的複雜度為o(n*len),實際查詢的複雜度只是o(len)。
解釋一下hash為什麼不能將建立與查詢同時執行,例如有串:911,911456輸入,如果要同時執行建立與查詢,過程就是查詢911,沒有,然後存入9、91、911,查詢911456,沒有然後存入9114、91145、911456,而程式沒有記憶功能,並不知道911在輸入資料中出現過。所以用hash必須先存入所有子串,然後for迴圈查詢。
而trie樹便可以,存入911後,已經記錄911為出現的字串,在存入911456的過程中就能發現而輸出答案;倒過來亦可以,先存入911456,在存入911時,當指標指向最後乙個1時,程式會發現這個1已經存在,說明911必定是某個字串的字首,該思想是我在做pku上的3630中發現的,詳見本文配套的「入門練習」。
[cpp]view plain
copy
print?
const
intbranchnum = 26;
//宣告常量
inti;
struct
trie_node
};
class
trie;
trie::trie()
void
trie::insert(
const
char
* word)
location = location->next[*word-'a'
];
word++;
} location->isstr = true
; //到達尾部,標記乙個串
} bool
trie::search(
char
*word)
return
(location!=null && location->isstr);
}
單詞的刪除:
[cpp]view plain
copy
print?
bool
trie::deleteword(
const
char
* word)
if(current && current->isstr)
} if(current->isstr == 0 && isnotvalid)
//當乙個節點無效,即它只和該word相關,可以刪除
else
//說明當前這個中間結點也被其他的結點所用,不能刪除。
nodes.top()->next[c - 'a'
] = 0;
//把上層的結點的next中指向current結點的指標清0
nodes.pop();
} return
true
; }
else
}
另外,貼乙個統計單詞的程式:
[cpp]view plain
copy
print?
/*檔名: trie.c
功能描述:用trie樹實現單詞詞頻統計以及單詞查詢
說明:對統計物件,要求符合正則"[a-z]*"的格式的單詞
若考慮大寫,標點和空白字元(空格.tab.回車換行符),
可修改next陣列大小,最多255可包含所有字元
*/#include
#include
#include
#include
using
namespace
std;
typedef
struct
trie_node_stru
trienode, *trie;
trienode* trie_createtrienode()
inttrie_insert(trie root,
char
* word)
node = node->next[*p-'a'
];
p++;
} node->count += 1;
, word, node->count);
return
0;
} int
trie_search(trie root,
char
* word)
return
(node!=null && node->count>0);
} int
trie_remove(trie root,
char
* word)
intmain()
"font-size:18px"
>
Trie樹的實現
一 定義 trie,又稱字典樹,是一種用於快速檢索的二十六叉樹結構。典型的空間換時間 二 結構圖 三 原理 特別地 和二叉查詢樹不同,在trie樹中,每個結點上並非儲存乙個元素。四 性質 0 利用串的公共字首,節約記憶體 1 在trie樹上進行檢索總是始於根結點 2 根節點不包含字元,除根節點外的每...
Trie樹的學習
所寫內容,是對自己所學知識的乙個記錄罷了。1.簡介 最近在做中國人名識別的時候,看到一篇文章是基於角色的人名識別,而角色字典中有2個角色是用雙陣列tire樹來建立的,當時沒有看懂,於是來先學習trie樹。trie樹,又稱字典樹,單詞查詢樹或者字首樹等,是一種快速 檢索的多叉樹結構。比如,英文本母的字...
可愛的Trie樹
鑑於ducati的建議下,講一下trie樹 見書p77 trie又被稱為字首樹 字典樹,所以當然是一棵樹。樹中的每一條邊上都標識有乙個字元。這些字元可以是任意乙個字符集中的字元。比如對於都是小寫字母的字串,字符集就是 a z 對於都是數字的字串,字符集就是 0 9 對於二進位制字串,字符集就是0和1...