上學期的一門程式設計課寫過幾個實驗程式,可惜由於懶散、能力等各方面問題,寫得都很粗糙,比如這個trie樹只是做了基本的實現,至多有一點點小技巧,效能其實很差。但還是寫點東西記錄一下,也是成長過程的一部分。
如果想在一大堆字串中找到某個特定的字串,最簡單的方法當然是暴力匹配,然而效率會低得嚇人,即使對於中等規模的資料量,其效能也是無法接受的。而trie樹採取了以空間換時間的策略(增加了一些指標域等額外資料,但也未必會增加儲存空間,例如有大量字串,每個字串長度為n個字元,前n-1個字元都是一樣的,只有最後乙個字元不同,那麼採用特定實現的trie樹反而會大大節省儲存空間),大大提高了字串匹配的速度,實現得當的話,複雜度與欲查詢的字串長度成比例,相對於暴力匹配,很明顯是乙個巨大的優化。
那麼,是如何實現的呢?暴力匹配之所以慢,是因為做了許多重複工作。例如,欲在查詢「abcd"字串,暴力匹配首先將第乙個字串"aaaa"與"abcd"比較,乙個乙個字元判斷是否相同,第乙個字元相同就判斷第二個,依此類推,直到匹配成功或者某個字元不同匹配失敗。然後繼續匹配第二個字串"bbbb",我們將"abcd"的第乙個字元'a'與其首字母'b'比較時,發現兩者不同,匹配失敗,再繼續匹配第三個字串。但是等等,我們為什麼要做這第二次比較呢?在與第乙個字串匹配時,我們已經知道了欲查詢字串"abcd"的首字母為'a',那麼,所有首字母不為'a'的字串都可以排除了,無須匹配,所以,第二次匹配是在做無用功。你可能會說,我不匹配怎麼知道某個字串首字母不是'a',不還是要進行匹配的嘛。於是,我們就需要先對原始資料做一些處理,提取出某些資訊,方便查詢。建立trie樹就是這個目的,根據每個字串的各個字母,將其劃分為不同的集合,這樣就縮小了範圍。例如,對於"abd"字串,當第乙個字元是'a',我們將其存入首字母為'a'的字串集合裡,第二個字元是'b',我們再將其存入(首字母為'a')第二個字元為'b'的集合裡,依此類推。trie樹建立完成後,查詢"abcd"字串,根據字串中每個字元進入相應的集合去尋找,當發現首字母為'a'時,就去首字母為'a'的集合裡匹配,"bbbb"字串儲存在另乙個集合裡,無須匹配,避免了無用功,提公升了效率。當然這裡所說的集合等只是乙個抽象的概念,具體實現時trie樹顧名思義當然是一棵樹,首字母為'a'的集合是指以相應節點為根的子樹。
如上圖,當確定首字母為'a'後,我們只需選擇最左邊的那棵子樹繼續向下匹配,其餘子樹不必理會。
在實現時,資料是儲存在節點中,而不是如圖中那樣,似乎是儲存在邊上的。在樹中,這些邊代表指標,一般無法儲存額外資訊。trie樹其實是一種概念,具體實現有多種方法,甚至可以不是一棵樹,其中一種常見的實現方式是雙陣列實現,用兩個陣列而不是樹來實現trie「樹」。如果用樹這種資料結構來實現的的話,很明顯的實現方法就是在樹的節點中儲存字元。這裡又有兩種選擇:第一種是在節點中用陣列或鍊錶只儲存出現過的字元,查詢時須遍歷,速度較慢,但節省空間;第二種是用雜湊表的形式儲存字元,速度較快,但占用空間較大,尤其是在字符集很大的情況下。trie樹本來就是用於處理大量字串的,並且常常需要很多空間開銷來換取時間,所以不宜再加大空間開銷。
trie樹-github
trie樹-oschina
這是乙個簡單的實現,分別上傳到了github和oschina,效能較低。有很多優化方法,但會掩蓋基本思想,討論trie樹的高效實現和優化不是本文的目的。
Trie樹(字典樹)
trie樹的核心思想是用空間換時間,通過在樹中儲存字串的公共字首,來達到加速檢索的目的。例如,對於一棵儲存由英文本母組成的字串的trie樹,如下圖 trie樹在實現的時候,可以用左兒子右兄弟的表示方法,也可以在每個節點處開設乙個陣列,如上圖的方法。trie樹的主要操作是插入 查詢,也可以進行刪除。插...
字典樹 Trie樹
字典樹 trie樹 顧名思義是一種樹形結構,屬於雜湊樹的一種。應用於統計 排序 查詢單詞 統計單詞出現的頻率等。它的優點是 利用字串的公共字首來節約儲存空間,最大限度地減少無謂的字串比較,查詢效率比雜湊表高。字典樹的結構特點 根節點不代表任何字元。其他節點從當前節點回溯到根節點可以得到它代表的字串。...
字典樹 trie樹
amy 56 ann 15 emma 30 rob 27 roger 52首先存入amy,level 0表示根,不持有資料。其餘每個節點持有乙個字元 葉子節點持有資料,且持有的字元為 0 level 0 root a level 1 m level 2 y level 3 0 56 level 4新...