PS:本人蒟蒻,欢迎大家指正错误
一,字典树(Trie-Tree)
定义:又名单词查找树,为树状结构,是哈希树的变种。利用字符串的公共前缀,在存储时节约空间,查询时节约时间,尽可能减少不必要的字符比较。
二,功能
1. 利用公共前缀存储大量字符串
2. 减少查找字符串时的比较
3. 查询一个字串s在字典中总共出现的次数
三,代码实现
利用字符与a的相对距离保存到整棵树中,a~z对应着0-25.
1. 字典树节点
1 //const int maxn=26; 2 struct TrieNode{ 3 int num;//共有多少个字符串经过该节点,即从根节点到该节点组成的字串出现次数 4 bool isEnd;//判断是否是一个字符串的结尾 5 struct TrieNode *son[maxn];//指向26棵子树 6 };
2. 建树函数
1 TrieNode *Build(){ 2 TrieNode *Head=new TrieNode;//创建头节点 3 Head->isEnd=false; //当前字典中没有字符串 4 Head->num=0; // 5 for(int i=0; i<maxn; i++){ 6 Head->son[i]=NULL;//将26个儿子均置为空 7 } 8 return Head; //返回根节点 9 }
3. 添加字符串函数
1 TrieNode *Update(TrieNode *head, string s){ 2 TrieNode *t=head; 3 int k=0; 4 while(t->son[s[k]-'a']!=NULL&& k<s.size()){//根据公共前缀向下查找 5 t->num++; 6 t=t->son[s[k]-'a']; 7 k++; 8 } 9 if(k==s.size()){ //说明新添加的字符串是字典中某串前缀的子串,添加结束标记 10 t->isEnd=true; 11 }else{ 12 while(k<s.size()){ //根据字符串添加新的节点 13 TrieNode *current=new TrieNode; 14 current->num=1; 15 current->isEnd=false; 16 for(int i=0; i<maxn; i++){ //其他方向均置为空 17 current->son[i]=NULL; 18 } 19 t->son[s[k]-'a']=current; 20 t=t->son[s[k]-'a']; 21 k++; 22 } 23 t->isEnd=true; //添加结束标记 24 } 25 return head; //返回根节点 26 }
4. 查找函数
1 bool Search(TrieNode *head, string s){ 2 TrieNode *current=head; 3 int k=0; 4 while(k<s.size()&¤t->son[s[k]-'a']!=NULL){//根据查找字符串向叶节点延申 5 current=current->son[s[k]-'a']; 6 k++; 7 } 8 if(k<s.size()) //说明该方向查找到叶节点而字符串未匹配完毕,说明没有 9 return false; 10 return current->isEnd;//字符串匹配完毕,返回结束标记 11 }
5. 公共前缀计数函数
1 int Counter(TrieNode *head, string str){ 2 TrieNode *current=head; 3 int k=0; 4 while(k<str.size()&¤t->son[str[k]-'a']!=NULL){//根据字符串向叶节点搜索 5 current=current->son[str[k]-'a']; 6 k++; 7 } 8 if(k<str.size()) 9 return -1; //意外结束 10 else 11 return current->num;//返回当前公共前缀的数量 12 }
6. 打印字典树(通过递归实现字典序打印)
1 void Output(TrieNode *head, string print){ 2 if(head->isEnd){ //已经形成一个单词,打印出来 3 cout<<print<<endl; 4 } 5 for(int i=0; i<maxn; i++){ //遍历26个方向 6 if(head->son[i]!=NULL){ 7 print+=('a'+i); 8 Output(head->son[i], print);//递归调用打印函数 9 print.erase(print.end()-1, print.end()); 10 } 11 } 12 }
代码整合:
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=26; 6 struct TrieNode{ 7 int num; 8 bool isEnd; 9 struct TrieNode *son[maxn]; 10 }; 11 12 TrieNode *Build(){ 13 TrieNode *Head=new TrieNode; 14 Head->isEnd=false; 15 Head->num=1; 16 for(int i=0; i<maxn; i++){ 17 Head->son[i]=NULL; 18 } 19 return Head; 20 } 21 22 TrieNode *Update(TrieNode *head, string s){ 23 TrieNode *t=head; 24 int k=0; 25 while(t->son[s[k]-'a']!=NULL&& k<s.size()){ 26 t=t->son[s[k]-'a']; 27 t->num++; 28 k++; 29 } 30 if(k==s.size()){ 31 t->isEnd=true; 32 }else{ 33 while(k<s.size()){ 34 TrieNode *current=new TrieNode; 35 current->num=1; 36 current->isEnd=false; 37 for(int i=0; i<maxn; i++){ 38 current->son[i]=NULL; 39 } 40 t->son[s[k]-'a']=current; 41 t=t->son[s[k]-'a']; 42 k++; 43 } 44 t->isEnd=true; 45 } 46 return head; 47 } 48 49 bool Search(TrieNode *head, string s){ 50 TrieNode *current=head; 51 int k=0; 52 while(k<s.size()&¤t->son[s[k]-'a']!=NULL){ 53 current=current->son[s[k]-'a']; 54 k++; 55 } 56 if(k<s.size()) 57 return false; 58 return current->isEnd; 59 } 60 /* 61 TrieNode *Erase(TrieNode *head, string s){ 62 TrieNode *current=head, *pre=head; 63 int k=0, n; 64 while(1){ 65 current=current->son[s[k]-'a']; 66 k++; 67 if(k>=s.size()) 68 break; 69 if(current->isEnd=true){ 70 n=k; 71 pre=current; 72 } 73 } 74 bool flag=false; 75 for(int i=0; i<maxn; i++){ 76 if(current->son[i]!=NULL) 77 flag=true; 78 } 79 if(flag) 80 current->isEnd=false; 81 else{ 82 n++; 83 current=pre->son[s[n]-'a']; 84 while(n<s.size()){ 85 TrieNode *tmp=current; 86 n++; 87 current=current->son[s[n]-'a']; 88 delete tmp; 89 } 90 } 91 return head; 92 } 93 */ 94 95 int Counter(TrieNode *head, string str){ 96 TrieNode *current=head; 97 int k=0; 98 while(k<str.size()&¤t->son[str[k]-'a']!=NULL){ 99 current=current->son[str[k]-'a']; 100 k++; 101 } 102 if(k<str.size()) 103 return -1; 104 else 105 return current->num; 106 } 107 108 void Output(TrieNode *head, string print){ 109 if(head->isEnd){ 110 cout<<print<<endl; 111 } 112 for(int i=0; i<maxn; i++){ 113 if(head->son[i]!=NULL){ 114 print+=('a'+i); 115 Output(head->son[i], print); 116 print.erase(print.end()-1, print.end()); 117 } 118 } 119 } 120 121 int main(){ 122 TrieNode *Head=Build(); 123 int n; 124 cin>>n; 125 string str; 126 for(int i=0; i<n; i++){ 127 cin>>str; 128 Head=Update(Head, str); 129 } 130 cin>>str; 131 if(Search(Head, str)){ 132 cout<<"Yes"<<endl; 133 //Head=Erase(Head, str); 134 } 135 else 136 cout<<"No"<<endl; 137 cout<<Counter(Head, str)<<endl; 138 string print; 139 Output(Head, print); 140 return 0; 141 }