Trie树也叫字典树,是一种用于快速检索的多叉树结构。如英文字母的字典树是一个26叉树。数字的字典树是一个10叉树。Trie树把要查找的关键词看作一个字符序列,并根据构成关键词字符的先后顺序构造用于检索的树结构;一棵m度的Trie树或者为空,或者由m棵m度的Trie树构成。特别的:和二叉查找树不同,在Trie树中,每个结点上并非存储一个元素。在Trie树中查找一个关键字的时间和树中包含的结点数无关,而取决于组成关键字的字符数。
特点:
①利用串的公共前缀->节约内存。
②根结点(root)不包含任何字母。
③其余结点仅包含一个字母(非元素)。
④每个结点的子结点包含字母不同。
查找过程:
①在Trie树上进行检索总是始于根结点。
②取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索。
③在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
④在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
字典树比较一般的实现是用指针,所以又可分为动态开辟内存的字典树和静态开辟内存的字典树。两种写法各有长处,一般静态的速度较快,而动态的代码较简。
动态模板:
#include <iostream> using namespace std; const int MAXM = 30,KIND = 26; int m; struct node { char* s; int prefix; bool isword; node* next[KIND]; node() { s = NULL; prefix = 0; isword = false; memset(next,0,sizeof(next)); } }*root;//根 void insert(node *root,char *s)//插入 { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; p->s = s+i; if (p->next[x] == NULL) p->next[x] = new node; p = p->next[x]; p->prefix++; } p->isword = true; } bool del(node *root,char *s)//删除 { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; if (p->next[x] == NULL) return false; p = p->next[x]; } if (p->isword) p->isword = false; else return false; return true; } bool search(node *root,char* s)//查找 { node* p = root; for (int i = 0;s[i];i++) { int x = s[i]-'a'; if (p->next[x] == NULL) return false; p = p->next[x]; } return p->isword; } int count(node *root,char *s)//统计后缀 { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; if (p->next[x] == NULL) return 0; p = p->next[x]; } return p->prefix; } int main() { m = 0; root = new node; char s[MAXM]; while (gets(s)) { if (strcmp(s,"") == 0) break; insert(root,s); } while (gets(s)) printf("%d ",count(root,s)); }
静态模板:
#include <iostream> using namespace std; const int MAXN = 100010,MAXM = 30,KIND = 26; int m; struct node { char* s; int prefix; bool isword; node* next[KIND]; void init() { s = NULL; prefix = 0; isword = false; memset(next,0,sizeof(next)); } }a[MAXN*MAXM],*root;//根 void insert(node *root,char *s) { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; p->s = s+i; if (p->next[x] == NULL) { a[m].init(); p->next[x] = &a[m++]; } p = p->next[x]; p->prefix++; } p->isword = true; } bool del(node *root,char *s) { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; if (p->next[x] == NULL) return false; p = p->next[x]; } if (p->isword) p->isword = false; else return false; return true; } bool search(node *root,char* s) { node* p = root; for (int i = 0;s[i];i++) { int x = s[i]-'a'; if (p->next[x] == NULL) return false; p = p->next[x]; } return p->isword; } int count(node *root,char *s) { node *p = root; for (int i = 0;s[i];i++) { int x = s[i] - 'a'; if (p->next[x] == NULL) return 0; p = p->next[x]; } return p->prefix; } int main() { m = 0; a[m].init(); root = &a[m++]; char s[MAXM]; while (gets(s)) { if (strcmp(s,"") == 0) break; insert(root,s); } while (gets(s)) printf("%d ",count(root,s)); }