字典树

 转载请注明出处,谢谢。http://www.cnblogs.com/acmer-roney/---by Roney

【本文摘自百度文库】

综述

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

性质

  它有3个基本性质: 

根节点不包含字符,除根节点外每一个节点都只包含一个字符。 

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

每个节点的所有子节点包含的字符都不相同。 

假设有abcabcdabd, b, bcdefghii7个单词,可构建字典树如下:

 

 

 

查找一个字符串时,我们只需从根结点按字符串中字符出现顺序依次往下走。如果到最后字符串结束时,对应的结点标记为红色,则该字符串存在;否则不存在。
插入时也只需从根结点往下遍历,碰到已存在的字符结点就往下遍历,否则,建立新结点;最后标记最后一个字符的结点为红色即可。

基本操作

  其基本操作有:查找 插入和删除 

实现方法

搜索字典项目的方法为:

  (1) 从根结点开始一次搜索; 

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

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

  (4) 迭代过程…… 

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

其他操作类似处理

View Code
  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    char* longest_prefix(Treenode *root, const char *word) //返回word的最长前缀
 65    {
 66        Treenode *location=root;
 67        int i=0,branch=0;
 68    
 69        if(location==NULL) return NULL;
 70    
 71        while(word[i])
 72        {
 73            branch=word[i]-'a';
 74            if(!location->next[branch]) break;
 75            location=location->next[branch];
 76            i++;
 77        }
 78        if(i == 0) return NULL;
 79        string str1 = string(word).substr(0, i);
 80        char *str = new char[str1.length()+1];
 81        strcpy(str,(char*)str1.c_str());
 82        return str;
 83    
 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    void remove(Treenode *root, const char *word)
129    {
130        Treenode *target = search(root, word);
131        if(!target) return ;
132        if(target->isColored)
133          target->isColored = false;
134        if(target->count == 0) { //如果target没有子节点,则将其从父节点中移除。(不做此步亦可)
135          target->parent->next[target->ch - 'a'] = NULL;
136        }
137    }
138    
139    void print(Treenode *root, char *str, int i) //输出所有(红色)节点
140    {
141        str[i] = root->ch;
142    
143        if(root->isColored)
144        {
145            str[i+1] = '\0';
146            puts(str+1);
147        }
148    
149        for(int j=0;j<kind;j++)
150        {
151            if(root->next[j]!=NULL)
152            {
153               print(root->next[j],str,i+1);
154            }
155        }
156    }
157    
158     
159    
160    int main()
161    {
162        char word[10];
163        char ask[10];
164        char str[20];
165        Treenode *root=NULL;
166        cout<<"input the strings to build the tire:\n";
167        while(gets(word))
168        {
169            if(word[0]=='\0') break;
170            insert(root,word);
171        }
172    
173        vector<char*> allElement;
174        vector<char*>::iterator pos;
175        getAll(root, str, 0, allElement);
176        for(pos = allElement.begin(); pos != allElement.end(); ++pos) {
177            cout<<"ab"<<*pos<<endl;
178        }
179        allElement.clear();
180        cout<<"所有以ab为前缀的红色结点:\n";
181        autocomplete(root, "ab", str, 0, allElement);
182        for(pos = allElement.begin(); pos != allElement.end(); ++pos) {
183            cout<<"ab"<<*pos<<endl;
184        }
185        //print(root, str, 0);
186        cout<<"abcd的最长前缀: ";
187        cout<<longest_prefix(root, "abcd")<<endl;
188        cout<<"input a string to search: ";
189        gets(ask);
190        search(root,ask) == NULL ? cout<<ask<<" is not found."<<endl : cout<<ask<<" is found."<<endl;
191        remove(root,ask);
192        cout<<"after delete "<<ask<<endl;
193        print(root, str, 0);
194        return 0;
195    }

 

posted on 2012-09-11 15:37  Acmer_Roney  阅读(199)  评论(0编辑  收藏  举报

导航