zoukankan      html  css  js  c++  java
  • trie树略解

    trie树也叫字典树,前缀树
    字典树(Trie)有如下几条性质

    1. 结点不存值,依靠树枝(边)存值
    2. 从根节点到某一处标记点为一个单词
    3. 每个结点到其子节点的边上的值各不相同
    4. 插入和查询复杂度均为O(mn),m为字符串个数,n为字符串平均长度
    5. 树深度由最长字符串决定

    依次便可做出trie树的结点结构

    struct trie{
    	int cnt=0;
    	bool word=0;
    	trie * son[26]={0};
    };
    

    让我们依次价绍这几个成员的含义

    1. cnt 这条边上有几个单词经过,即有多少指定的前缀相同的单词
    2. word 从根节点这个结点是否是一个单词
    3. son[26] 其子节点的地址;

    依据其基本性质和结构体成员,写出构造函数如下

    void make()
    {
     string s;
     cin>>s;
     int lo=s.lenth();
     trie * now=root;
     for(int i=0;i<lo;i++){
       if(now->son[s[i]-'a']) now = now->son[s[i]-'a'];
       else {
         now->son[s[i]-'a']=new trie;
         now=now->son[s[i]-'a'];
       }
       now->cnt++;
     }
     now->word=1;
    }
    

    首先读入一个字符串,得到其长度,并将查询指针调至根节点
    这时从字符串第一个字符开始查询该字符是否已经存过
    如果存过则将查询指针所在结点的cnt++,并移至该节点,如果未存过,则申请一个新结点连接到相应位置上
    直到最后一个结点,将最后一个结点中的word标记改为1

    根据trie树性质同时可写出查询函数

    void check()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s),i;
    	trie * now=root;
    	for(i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			printf("NO
    ");
    			break;
    		}
    	}
    	if(i == lo){
    		printf("YES
    ");
    	}
    }
    

    首先读入需要查询的字符串,按生成树的方式判断是否存过某字符,若存过,则进入所存结点
    若未存过,则break,防止访问空指针,若只判断是否含有某前缀,则上述函数可完成,查询单词时,可将最后一处判断改为

    if(i == lo && now->word){
    	printf("YES
    ");
    }
    else{
    	printf("NO
    ");
    }
    

    即当循环结束,字符串在树中时,判断是否这个字符串是整个单词

    当树生成时,自动实现字符串的排序
    可用递归实现
    同时可用递归实现树的删除

    与hash比较

    Trie 的强大之处就在于它的时间复杂度。O(n),与 Trie 中保存了多少个元素无关。
    Hash 表号称是 O(1) 的,但在计算 hash 的时候就肯定会是 O(n) ,而且还有可能冲突的问题
    Trie 的缺点是空间消耗很高。

    trie树拓展

    AC自动机

    为trie树上的KMP,留于KMP处详解

    后缀树

    可实现后缀自动机

    基数数

    将二进制数拆成几个2位数或几个4位数,按trie树方式存入
    好像没什么卵用

    trie树例题:

    洛谷 2580
    题解

    #include<cstdio>
    #include<cstring>
    using namespace std;
    struct trie{
    	bool check=0;
    	bool word=0;
    	trie * son[26]={0};
    };
    trie *root;
    void make()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s);
    	trie * now=root;
    	for(int i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			now->son[s[i]-'a']=new trie;
    			now=now->son[s[i]-'a'];
    		}
    	}
    	now->word=1;
    }
    
    void check()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s),i;
    	trie * now=root;
    	for(i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			printf("WRONG
    ");
    			break;
    		}
    	}
    	if(i == lo && now->word){
    		if(now->check){
    			printf("REPEAT
    ");
    		}
    		else{
    			printf("OK
    ");
    			now->check=1;
    		}
    	}
    }
    
    int main()
    {
    	root = new trie;
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		make();
    	}
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		check();
    	}
    	return 0;
    }
    

    codevs 4189
    题解:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    struct trie{
    	trie * son[26];
    };
    trie *root;
    void make()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s);
    	trie * now=root;
    	for(int i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			now->son[s[i]-'a']=new trie;
    			now=now->son[s[i]-'a'];
    		}
    	}
    }
    
    void check()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s),i;
    	trie * now=root;
    	for(i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			printf("NO
    ");
    			break;
    		}
    	}
    	if(i == lo){
    		printf("YES
    ");
    	}
    }
    
    int main()
    {
    	root = new trie;
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		make();
    	}
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		check();
    	}
    	return 0;
    }
    

    hihocoder 1014

    #include<cstdio>
    #include<cstring>
    using namespace std;
    struct trie{
    	int cnt=0;
    	trie * son[26]={0};
    };
    trie a;
    trie *root=&a;
    void make()
    {
    	char s[15];
    	scanf("%s",s);
    	int lo=strlen(s);
    	trie * now=root;
    	for(int i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			now->cnt++;
    			continue;
    		}
    		else {
    			now->son[s[i]-'a']=new trie;
    			now=now->son[s[i]-'a'];
    			now->cnt++;
    		}
    	}
    }
    void check()
    {
    	char s[55];
    	scanf("%s",s);
    	int lo=strlen(s),i;
    	trie * now=root;
    	for(i=0;i<lo;i++){
    		if(now->son[s[i]-'a']){
    			now = now->son[s[i]-'a'];
    			continue;
    		}
    		else {
    			printf("0
    ");
    			break;
    		}
    	}
    	if(i == lo){
    		printf("%d
    ",now->cnt);
    	}
    }
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		make();
    	}
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		check();
    	}
    	return 0;
    }
    
  • 相关阅读:
    制作在线简历(一)——Loading与底部菜单
    然而这并没有什么卵用
    移动开发中Fiddler的那些事儿
    多种方法实现Loading(加载)动画效果
    总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解
    SQLServer和MySQL job和 event定时器的差别
    全局ID的重要性
    Windows操作系统上各种服务使用的端口号, 以及它们使用的协议的列表
    Linux发展历史图
    奇特的Local System权限(转载)
  • 原文地址:https://www.cnblogs.com/shulker/p/9470502.html
Copyright © 2011-2022 走看看