Trie樹
--------------------------------------------------------------------------------
Trie樹,又稱單詞查找樹、字典樹,是一種樹形結構,是一種哈希樹的變種,是一種用於快速檢索的多叉樹結構。典型應用是用於統計和排序大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。
Trie樹的優點是:最大限度地減少無謂的字符串比較,查詢效率比哈希表高。 Trie的核心思想是空間換時間。利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的。 Trie樹也有它的缺點,Trie樹的內存消耗非常大.
Trie樹的結構特點:
1.root結點沒有數據
2.除根結點外每個結點只包含一個字符
3.從根結點到某一個結點正好組成一個字符串
Trie樹的大致結構如下:
Trie樹的實現
下面是一個簡單的Trie樹的實現,假定只包括26個字符,忽略大小寫。
--------------------------------------------------------------------------------
#include <stdlib.h> class Trie{ public: Trie(); ~Trie(); int insert(const char* str); int search(const char* str)const; int remove(const char* str); static const int CharNum = 26; protected: typedef struct s_Trie_Node{ bool isExist; struct s_Trie_Node* branch[Trie::CharNum]; s_Trie_Node(); }Trie_Node; Trie_Node* root; }; Trie::Trie():root(NULL){} Trie::~Trie(){} Trie::s_Trie_Node::s_Trie_Node():isExist(false){ for(int i = 0; i < Trie::CharNum; ++i){ branch[i] = NULL; } } int Trie::insert(const char* str){ if(root == NULL){ root = new Trie_Node(); } Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } if(pos->branch[ char_pos] == NULL){ pos->branch[ char_pos ] = new Trie_Node(); } pos = pos->branch[ char_pos ]; str++; } if(pos->isExist){ return 0; } else { pos->isExist = true; return 1; } } int Trie::search(const char* str)const{ Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } pos = pos->branch[char_pos]; str++; } if(pos != NULL && pos->isExist){ return 1; } else { return 0; } } int Trie::remove(const char* str){ Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } pos = pos->branch[ char_pos ]; str++; } if(pos != NULL && pos->isExist){ pos->isExist = false; return 1; } else { return 0; } } #include <stdlib.h> class Trie{ public: Trie(); ~Trie(); int insert(const char* str); int search(const char* str)const; int remove(const char* str); static const int CharNum = 26; protected: typedef struct s_Trie_Node{ bool isExist; struct s_Trie_Node* branch[Trie::CharNum]; s_Trie_Node(); }Trie_Node; Trie_Node* root; }; Trie::Trie():root(NULL){} Trie::~Trie(){} Trie::s_Trie_Node::s_Trie_Node():isExist(false){ for(int i = 0; i < Trie::CharNum; ++i){ branch[i] = NULL; } } int Trie::insert(const char* str){ if(root == NULL){ root = new Trie_Node(); } Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } if(pos->branch[ char_pos] == NULL){ pos->branch[ char_pos ] = new Trie_Node(); } pos = pos->branch[ char_pos ]; str++; } if(pos->isExist){ return 0; } else { pos->isExist = true; return 1; } } int Trie::search(const char* str)const{ Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } pos = pos->branch[char_pos]; str++; } if(pos != NULL && pos->isExist){ return 1; } else { return 0; } } int Trie::remove(const char* str){ Trie_Node* pos = root; int char_pos; while(pos != NULL && *str != '\0'){ if(*str >= 'a' && *str <= 'z'){ char_pos = *str - 'a'; } else if(*str >= 'A' && *str <= 'Z'){ char_pos = *str - 'A'; } else { return -1; } pos = pos->branch[ char_pos ]; str++; } if(pos != NULL && pos->isExist){ pos->isExist = false; return 1; } else { return 0; } }
Trie樹的應用
--------------------------------------------------------------------------------
1. 大量字符串的統計,查找
用的比較多的場合,例如:搜索引擎對文本中詞頻的統計,搜索引擎日志對用戶關鍵詞搜索頻率的統計,等等。下面討論兩道經典的面試題:
1.找出大量日志文件中,出現次數前10的網址。
這個問題使用Trie樹再適合不過了,對於大量日志文件的統計,使用trie樹速度相當快。結合最小堆和trie樹,對日志文件搜索一次就可以得到結果。
2.實現一個網站的輸入提示功能
這個問題需要在用戶輸入的時候,實時展示輸入建議,使用trie樹可以輕松實現。
2.字符串的排序
對於大規模字符串的排序,只需要統計一次字符串,構造trie樹,然後遍歷輸出就得到排序結果。
3.找字符串的最長公共前綴
這個問題顯而易見。