字典树(TrieTree)

1. 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

2. Trie Tree的性质:

  (1)根节点不包含字符,除根节点外每一个节点包含一个字符。

  (2)从根节点到某一节点,路径数经过的字符连接起来,为该节点对应的字符串。

  (3)每个节点的子节点包含的字符均不相同。

3. 基本操作主要是插入和查找,偶尔涉及删除操作。

4. 实现方法,搜索字典树项目的方法为:

  (1)从根节点开始依次搜索。

  (2)取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行查找。

  (3)在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行查找。

  (4)迭代过程。。。

  (5)在某个节点处,关键词的所有字母已被取出,则读取附在该节点山的信息,即查找完成。

5. 应用:主要是进行字符串的快速查找。将已有的单词建立成一棵字典树,在这棵字典树查找新的单词是否存在等。

6. 图示:

  

7. 完整的示例代码:

  1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4 
  5 const int kind=26;//字母种类
  6 
  7 struct Treenode//树的结点结构
  8 {
  9     char ch;  //节点处的字符
 10     bool isColored; //是否标记为红色,红色表示叶节点
 11     int count;  //子节点个数,记录一组字符串中某前缀出现的次数
 12     Treenode *next[kind];//指向子结点
 13     Treenode *parent;  //父节点
 14     Treenode(char thech, Treenode* par)//结点初始化
 15     {
 16         ch=thech;
 17         isColored=false;
 18         count=0;
 19         parent=par;
 20         for(int i=0;i<kind;i++)
 21             next[i]=NULL;
 22     }
 23 };
 24 
 25 void insert(Treenode *&root,char *word)    //向以root为根结点的树中插入串word
 26 {
 27     Treenode *location=root;
 28     int i=0,branch=0;
 29 
 30     if(location==NULL) {
 31         location=new Treenode(' ', NULL); //根节点字符为空,用空格(' ')表示
 32         root=location;
 33     }
 34 
 35     while(word[i])
 36     {
 37         branch=word[i]-'a';
 38         if(!location->next[branch])
 39             location->next[branch]=new Treenode(word[i], location);//如果不存在,建新结点
 40         location->count++;
 41         location=location->next[branch];
 42         i++;
 43     }
 44     location->isColored = true; //标记节点为叶节点
 45 }
 46 
 47 Treenode* search(Treenode *root,const char *word)//查找,找到则返回相应节点指针
 48 {
 49     Treenode *location=root;
 50     int i=0,branch=0;
 51 
 52     if(location==NULL) return NULL;
 53 
 54     while(word[i]){
 55         branch=word[i]-'a';
 56         if(!location->next[branch]) return NULL;
 57         location=location->next[branch];
 58         i++;
 59     }
 60     if(location->isColored)   return location;
 61     return NULL;
 62 }
 63 
 64 //返回word在已经建立的trie tree中的最长前缀
 65 char* longest_prefix(Treenode *root, const char *word) 
 66 {
 67     Treenode *location=root;
 68     int i=0,branch=0;
 69 
 70     if(location==NULL) return NULL;
 71 
 72     while(word[i])
 73     {
 74         branch=word[i]-'a';
 75         if(!location->next[branch]) break;
 76         location=location->next[branch];
 77         i++;
 78     }
 79     if(i == 0) return NULL;
 80     string str1 = string(word).substr(0, i);
 81     char *str = new char[str1.length()+1];
 82     strcpy(str,(char*)str1.c_str());
 83     return str;
 84 }
 85 
 86 //获取所有以root为根的(红色)结点,并存放到allElement中
 87 vector<char*> getAll(Treenode *root, char *str, int i, vector<char*> &allElement)
 88 {
 89     str[i] = root->ch;
 90 
 91     if(root->isColored)
 92     {
 93         str[i+1] = '\0';
 94         char *temp = (char*)malloc(strlen(str)*sizeof(char));
 95         strcpy(temp, str+1);//根节点不存字符,所以从第二个节点开始拷贝
 96         //temp[strlen(str)-1]='\0';
 97         allElement.push_back(temp);
 98     }
 99 
100     for(int j=0;j<kind;j++)
101     {
102         if(root->next[j]!=NULL)
103         {
104             getAll(root->next[j],str,i+1, allElement);
105         }
106     }
107     return allElement;
108 }
109 
110 //获取所有以word为前缀的红色结点,并存放到allElement中(不包含前缀,使用时需额外添加)
111 void autocomplete(Treenode *root, const char *word, char *str, int i, vector<char*> &allElement)
112 {
113     Treenode *location=root;
114     int j=0,branch=0;
115 
116     if(location==NULL) return ;
117 
118     while(word[j])
119     {
120         branch=word[j]-'a';
121         if(!location->next[branch]) return ;
122         location=location->next[branch];
123         j++;
124     }
125     getAll(location, str, i, allElement);
126 }
127 
128 //删除一个单词
129 void remove(Treenode *root, const char *word)
130 {
131     Treenode *target = search(root, word);
132     if(!target) return ;
133     if(target->isColored)
134         target->isColored = false;
135     if(target->count == 0) { //如果target没有子节点,则将其从父节点中移除。(不做此步亦可)
136         target->parent->next[target->ch - 'a'] = NULL;
137     }
138 }
139 
140 //打印树中所有的单词
141 void print(Treenode *root, char *str, int i) //输出所有(红色)节点
142 {
143     if (root==NULL)
144     {
145         return ;
146     }
147     str[i] = root->ch;
148 
149     if(root->isColored)
150     {
151         str[i+1] = '\0';
152         puts(str+1);
153     }
154 
155     for(int j=0;j<kind;j++)
156     {
157         if(root->next[j]!=NULL)
158         {
159             print(root->next[j],str,i+1);
160         }
161     }
162 }
163 
164 //删除这棵树
165 void deleteTree(Treenode* &root)
166 {
167     if (root==NULL)
168     {
169         return ;
170     }
171     for (int i=0;i<kind;i++)
172     {
173         if (root->next[i])
174         {
175             deleteTree(root->next[i]);
176         }
177     }
178     delete root;
179     root=NULL;
180 }
181 
182 int main()
183 {
184     char word[10];
185     char ask[10];
186     char str[20];
187     Treenode *root=NULL;
188     cout<<"input the strings to build the tire:\n";
189     while(gets(word))
190     {
191         if(word[0]=='\0') break;
192         insert(root,word);
193     }
194 
195     vector<char*> allElement;
196     vector<char*>::iterator pos;
197     getAll(root, str, 0, allElement);
198     //输出字典中的所有单词
199     for(pos = allElement.begin(); pos != allElement.end(); ++pos) {
200         cout<<*pos<<endl;
201     }
202     allElement.clear();
203     cout<<"所有以ab为前缀的红色结点:\n";
204     autocomplete(root, "ab", str, 0, allElement);
205     for(pos = allElement.begin(); pos != allElement.end(); ++pos) {
206         cout<<"ab"<<*pos<<endl;
207     }
208     cout<<"abcd的最长前缀: ";
209     cout<<longest_prefix(root, "abcd")<<endl;
210     cout<<"input a string to search: ";
211     gets(ask);
212     search(root,ask) == NULL ? cout<<ask<<" is not found."<<endl : cout<<ask<<" is found."<<endl;
213     remove(root,ask);
214     cout<<"after delete "<<ask<<endl;
215     print(root, str, 0);
216     deleteTree(root);
217     return 0;
218 }

8. 参考文章:

http://baike.baidu.com/view/2759664.htm

 

posted @ 2012-08-31 13:46  kasuosuo  阅读(605)  评论(0编辑  收藏  举报