Tire学习总结

一.tire树简介
ie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串,
所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
    Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符。
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
每个节点的所有子节点包含的字符都不相同。




二.Tire树结构示意图如下(红点标记的是一个单词的结尾),我们可以很清楚的看到,树中包含了所有的单词,
单词起点都是第一行,所以说Tire树利用的是公共前缀。



三.实现方法(其实Tire树的写法很模板化)
首先我们需要一个结构体来保存每个节点的子树(下面的写法是给一些单词,查询某个单词在不在所给的词里)
	struct tire
	{
		tire *next[maxn];			//保存子树节点,maxn为多大看题意,0-9的数字10就可以了,小写字母26就可以了
	bool isword;					//标记单词结尾
	}* root;					//root是根节点


然后有一个插入的单词的函数,这个很容易

	void insert(char *s)
	{
		tire *head = root;
		for(int i = 0;s[i] != '\0';++i)
		{
			int id = s[i]-'a';					//减去多少得看题意
			if(head->next[id] == NULL)				//为NULL时分配内存
			{
				head->next[id] = new tire();
				head->next[id]->isword = false;
			}
			head = head->next[id];
		}
		head->isword = true;
	}

接下来我们需要一个查询单词的函数

	bool query(char *s)
	{
		tire *head = root;
		for(int i = 0;s[i] != '\0';++i)
		{
			int id = s[i]-'a';
			if(head->next[id] == NULL)		//为空时说明找不到了
				return false;
			head = head->next[id];
		}
		if(head->isword)
			return true;
		return false;
	}


最后就是需要一个释放内存的函数,对于多组测试,这个是很有必要的,否则很可能爆内存

<span style="white-space:pre">	</span>void del(tire *head)
	{
		for(int i = 0;i < maxn;++i)
		{
			if(head->next[i] != NULL)
				del(head->next[i]);
		}
		delete head;
	}


这样Tire树的基本操作就完成了,当然在应用的时候还是得有些变化

四.我们现在看几个例题
HDU1251 --- 统计难题

http://acm.hdu.edu.cn/showproblem.php?pid=1251

只需把结构体里的bool isword;改成一个整型变量保存这个字串出现的次数就可以啦

/*
author: tpbluesky
time:   
题解:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;

struct trie
{
    trie *next[26];
    int num; 
};
trie *root;
void insert(char *s)
{
    trie *head = root;
    for(int i = 0;s[i] != '\0';i++)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
        {
            head->next[id] = new trie();
            head->next[id]->num = 1;
        }
        else
        {
            head->next[id]->num++;
        }
        head = head->next[id];
    }
}

int search(char *s)
{
    trie *head = root;
    for(int i = 0;s[i] != '\0';i++)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
            return 0;
        head = head->next[id];    
    }
    return head->num;
}

int  main()
{
    char s[15];
    root = new trie();
    while(gets(s) && s[0] != '\0')
        insert(s);
    while(gets(s) != NULL)
        cout<<search(s)<<endl;
    return 0;
}



HDU1671  phone list

http://acm.hdu.edu.cn/showproblem.php?pid=1671

注意要用del函数就可以了

/*
author: tpbluesky
time:   
题解:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
const int maxn = 10;

struct tire
{
    tire *next[10];
    bool isword;
};
tire *root;

int insert(char *s)
{
    tire *head = root;
    for(int i = 0;s[i] != '\0';++i)
    {
        int id = s[i]-'0';
        if(head->next[id] == NULL)
        {
            head->next[id] = new tire(); 
            head->next[id]->isword = false;
        }
        else
        {
            if(head->next[id]->isword)
                return 1;
        }
        head = head->next[id]; 
    }
    
    for(int i= 0;i < 10;++i)
        if(head->next[i] != NULL)
            return 1;
    head->isword = true;
    return 0;
}

void del(tire *head)
{
    for(int i = 0;i < 10;++i)
    {
        if(head->next[i] != NULL)
            del(head->next[i]);
    }
    delete head;
}

int main()
{
    int T, n;
    char s[15];
    cin>>T;
    while(T--)
    {
        root = new tire();
        scanf("%d",&n);
        int flag = 1;
        for(int i = 0;i < n ;++i)
        {
            scanf("%s",s);
            if(flag && insert(s))
            {
                flag = 0;
            } 
        }
        printf(flag?"YES\n":"NO\n");
        del(root);
    }
    return 0;
}

HDU1247 --- Hat's Words

http://acm.hdu.edu.cn/showproblem.php?pid=1247

查找时把单词拆开成两个单词,分别找就可以了,然后就是按字典序输出

/*
author: tpbluesky
time:   
题解:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
const int maxn = 50005;
char s[maxn][20];

struct tire
{
    tire *next[26];
    bool isword;
};
tire *root;

void insert(char *s)
{
    tire *head = root;
    for(int i = 0;s[i] != '\0';++i)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
        {
            head->next[id] = new tire();
            head->next[id]->isword = false;
        }
        head = head->next[id]; 
    }
    head->isword = true;
}

bool search(char *s)
{
    tire *head = root;
    int len = strlen(s);
    for(int i = 0;i < len;++i)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
            return false;
        head = head->next[id];
    }
    if(head->isword)
        return true;
    return false;
}

set<string> se;
int main()
{
    char str[100];
    int cnt = 0;
    root = new tire();
    while(scanf("%s",str) == 1)
    {
        strcpy(s[cnt++],str);
        insert(str);
    }
    for(int i = 0;i < cnt;++i)
    {
        int len = strlen(s[i]);
        for(int j = 1;j < len;++j)
        {
            strcpy(str,s[i]+j);
            char s1[15];
            strcpy(s1,s[i]);
            s1[j] = '\0';
            if(search(s1) && search(str))
                se.insert(string(s[i]));
        }
    }
    for(set<string>::iterator it = se.begin();it != se.end();++it)
        cout<<*it<<endl;
    return 0;
}


HDU4287 --- Intelligent  IME

http://acm.hdu.edu.cn/showproblem.php?pid=4287

查找的方法注意一下就可以啦,有的是一对三位,有的是一对四位,用递归比较好些

/*
author: tpbluesky
time:   
题解:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
const int maxn = 5005;
char s[maxn][10];
int n, m, cnt;
char stemp[10][10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
struct tire
{
    tire *next[26];
    int isword;
};
tire *root; 

void insert(char *s)
{
    tire *head = root;
    for(int i = 0;s[i] != '\0';++i)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
        {
            head->next[id] = new tire();
            head->next[id]->isword = 0;
        }
        head = head->next[id];
    }
    head->isword++;
}

void search(tire *head,char *s,int cur)
{
    if(cur >= strlen(s))
    {
        cnt += head->isword; 
        return;
    }
    int id = s[cur]-'0';
    for(int i = 0;i < strlen(stemp[id]);++i)
    {
        int t = stemp[id][i]-'a';
        if(head->next[t] != NULL)
            search(head->next[t],s,cur+1);
    }
}

void del(tire *head)
{
    for(int i = 0;i < 26;++i)
    {
        if(head->next[i] != NULL)
            del(head->next[i]);
    }
    delete head;
}

int main()
{
    char s1[10];
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        root = new tire();
        for(int i = 0;i < n;++i)
            scanf("%s",s[i]);
        for(int i = 0;i < m;++i)
        {
            scanf("%s",s1);
            insert(s1);
        }
        for(int i = 0;i < n;++i)
        {
            cnt = 0;
            search(root,s[i],0);
            printf("%d\n",cnt);
        }    
        del(root);
    }
    return 0;
}


HDU2846 ------  Repository

点击打开链接

考虑到查询的串是子串,而不是前缀字串,因此把所有字串也加到Tire树里面,但是统计又出现问题了,可能会重复统计

可以在结构体里加一个变量,记录当前是操作哪个串,如果操作的同一串,就不用统计,不是同一串就统计,并且更新记录到当前串

/*
author: tpbluesky
time:   
题解:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;

struct tire
{
    tire *next[26];
    int v, num; 
} *root;

void insert(char *s,int k)
{
    tire *head = root;
    for(int i = 0;s[i] != '\0';++i)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
        {
            head->next[id] = new tire();
            head->next[id]->v = 1;
            head->num = k;
        }
        else
        {
            if(k != head->next[id]->num)
            {
                head->next[id]->v++;
                head->next[id]->num = k;
            }        
        }
        head = head->next[id];
    } 
}

int query(char *s)
{
    tire *head = root;
    for(int i = 0;s[i] != '\0';++i)
    {
        int id = s[i]-'a';
        if(head->next[id] == NULL)
            return 0;
        head = head->next[id];
     } 
     return head->v;
}

int main()
{
    int n, m;
    char s[25], ss[25];
    scanf("%d",&n);
    root = new tire();
    for(int i = 0;i < n;++i)
    {
        scanf("%s",s);
        for(int j = 0;j < strlen(s);++j)
        {
            strcpy(ss,s+j);
            insert(ss,i);
        }
            
    }
    scanf("%d",&m);
    for(int i = 0;i < m;++i)
    {
        scanf("%s",s);
        printf("%d\n",query(s));
    }
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值