字典树.

字典树又叫前缀树.

干嘛的呢?

就一条,方便查询数据的.   具体的效率可是很让人大吃一惊的. 大吃一惊到什么层度呢?  几近于常数时间就可以查询任何我们想查询的东西.

具体可以干诸如:从大量数据中查询特定元素(常数时间).....好像只有这一个用法?

为什么呢?

其实啊,它是由树结构来组织的,而正是基于树的组织的高效性,就有了我们这个前缀树的应用了.

在一般的教科书式的讲解中,都是千篇一律的由线来表示元素,为什么呢? 这个问题先不回答!

下面我们先看看如何来实现字典树的构建和它被构建之后的用法(查询):

 1 #include<iostream>
 2 #include<string>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=1200;
 6 int a[maxn][26];//点对应的数据结构,26表示某点的分支.
 7 bool color[maxn];//点标记数组
 8 int len=1;//元素个数.
 9 void insert(string s)
10 {//插入
11     int ind=0;
12     for(int i=0;i<s.length();i++)
13     {
14         if(a[ind][s[i]-'a']) ind=a[ind][s[i]-'a'];//有的话
15         else a[ind][s[i]-'a']=len++,ind=a[ind][s[i]-'a'];//没的话
16     }
17     color[ind]=true;//标记是否是某个字串的结尾.
18 }
19 bool search(string s)
20 {//查找
21     int ind=0;
22     for(int i=0;i<s.length();i++)
23     {
24         if(!a[ind][s[i]-'a']) return false;//没的话
25         ind=a[ind][s[i]-'a'];//有的话
26     }
27     return color[ind];
28 }
29 int main()
30 {
31     memset(a,0,sizeof(a));
32     memset(color,0,sizeof(color));
33     int n,q;
34     string s;
35     cin>>n>>q;
36     while(n--)
37     {
38         cin>>s; insert(s);
39     }
40     while(q--)
41     {
42         cin>>s; 
43         if(search(s)) cout<<"yes"<<endl;
44         else cout<<"no"<<endl;
45     }
46     return 0;
47 }

可以看出以上的树结构的空间消耗是maxn*set(S)+maxn;

时间消耗除了建树外,只有常数的时间.

由此可知,时间消耗还是挺大的.且以上代码有个致命的缺点,那就是:  内存是固定分配的...

下面实现动态内存分配:

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
struct node
{//树的孩子表示法.一般型.
    int sign;//信号位,表示字符串结尾
    node* a[26];//后继结点
    node(){
        sign=0; for(int i=0;i<26;i++) a[i]=NULL;
    }
};
node* head=new node;//字典树的头部.
void insert(string s)
{//插入
    node* ind=head;
    for(int i=0;i<s.length();i++)
    {
        if(ind->a[s[i]-'a']) ind=ind->a[s[i]-'a'];
        else {
            node* p=new node;
            ind->a[s[i]-'a']=p;
            ind=p;
        }
    }
    ind->sign=1;
}
bool search(string s)
{//查找.
    node* ind=head;
    for(int i=0;i<s.length();i++)
    {
        if(ind->a[s[i]-'a']==NULL) return false;
        else  ind=ind->a[s[i]-'a'];
    }
    return ind->sign==1;
}
void del(node* ind)
{//删除操作.
    if(ind==0) return ;
    for(int i=0;i<26;i++) del(ind->a[i]);
    delete ind;
}
int main()
{
    string s;
    int n,q;
    cin>>n>>q;
    while(n--)
    {
        cin>>s; insert(s);
    }
    while(q--)
    {
        cin>>s; if(search(s)) cout<<"yes"<<endl;else cout<<"no"<<endl;
    }
    del(head);
    return 0;
}

可见,这样并不能简化空间,反而加大了代码复杂度.

不过这带来了一个好处,那就是:空间动态分配了!

其实我们要想优化空间的话,可以按照另外一种树的孩子表示法!双线性表方法.结点存储在数组中,其后继结点用链表连接,不过...这样的话较难维护.当然,也不算复杂.

最后我们再次强调!!!!!!!!!!!!!!!!!

它用途是加速查找!!!

其实我们的二叉搜索树(logn),平衡二叉树(logn),红黑树(logn)等等都是用来进行加快查找的!

我们讲理论联系实践,凡是跟实际不相干的事物也不会在人们的视野中.

一个事物的出现必然有某种社会因素的促进,而这这种促进带来的影响是其科学依据的.

比如元朝的腐败刻薄导致了朱同学的罢课, 清政府的没落导致了某党的执政, 再比如西方中世纪的稳定导致了文艺复兴,蒸汽机的出现导致了西方第一次工业革命的兴盛等等.

凡是存在的必然是合理的. 因为事物的产生都不是突变的,而是渐变的.

看看我们的网络技术发展,究其缘由还是资本的需要,资本把它的触手伸到了新一代代表世界高新科技的网络领域,以期获得更大的利益

而正是为了迎合资本的需要,才有了千千万万的创业者在前赴后继地挤破脑袋的冲入这一高新领域. 才有了众多科技人员从事it行业,才有中国乃至全世界各地区大量的学校开办计算机专业.

哎,究其根本,大家都只不过是资本的爪牙同时也是它的受害者.

没办法,时代如此,谁能左右呢?

既然存在即是合理,那就顺应时代吧.如果不这样,还能如何呢?

我说以上的东西不是想让大家对人生心灰意冷,只是想让大家知道既然时代如此,我们没法改变,那就应该积极入世,把自己应该做的给做好.

好好学习各项计算机技术,把力所能及的是做好,把想把握的事把握住,把想挽留的人挽留.毕竟人生也不只是工作和学习,不是吗?

posted @ 2020-03-05 22:24  SSXFC  阅读(171)  评论(0编辑  收藏  举报