字典树

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()&&current->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()&&current->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()&&current->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()&&current->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 }

 

转载于:https://www.cnblogs.com/Scotton-Wild/p/10309992.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值