1. 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
2. Trie Tree的性质:
(1)根节点不包含字符,除根节点外每一个节点包含一个字符。
(2)从根节点到某一节点,路径数经过的字符连接起来,为该节点对应的字符串。
(3)每个节点的子节点包含的字符均不相同。
3. 基本操作主要是插入和查找,偶尔涉及删除操作。
4. 实现方法,搜索字典树项目的方法为:
(1)从根节点开始依次搜索。
(2)取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行查找。
(3)在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行查找。
(4)迭代过程。。。
(5)在某个节点处,关键词的所有字母已被取出,则读取附在该节点山的信息,即查找完成。
5. 应用:主要是进行字符串的快速查找。将已有的单词建立成一棵字典树,在这棵字典树查找新的单词是否存在等。
6. 图示:
7. 完整的示例代码:
1 #include2 #include 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 ) 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 ) 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 ) 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 ) 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< "abcd")<<endl; 210 cout<<"input a string to search: "; 211 gets(ask); 212 search(root,ask) == NULL ? cout< " is not found."< " is found."<<endl; 213 remove(root,ask); 214 cout<<"after delete "< endl; 215 print(root, str, 0); 216 deleteTree(root); 217 return 0; 218 }
8. 参考文章:
http://baike.baidu.com/view/2759664.htm