Tire字典树

1、定义:

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

2、性质:

根节点不包含字符,除根节点外每一个节点都只包含一个字符;

从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

每个节点的所有子节点包含的字符都不相同。

3、操作实现(查询,插入时,一个字符串s,指针p指向根节点)

(1)初始化

Tire树仅包含一个节点,该点的字符指向均为空

(2) 插入

插入一个字符串s,令指针p指向根节点,依次扫描s中的字符

1.p指针的c字符指向一个已经存在的节点Q,令p=Q;

2.p指针的c字符指向空,建立一个新节点Q,令p=Q;

3.最后扫描完毕后当前节点指针p上标记的是字符串的末尾

(3)查找

1.p的c字符指针指向空,说明没有插入,结束查询。

2.p的c字符指针指向一个已经存在的节点Q,令p=Q;

3.当指针s中的字符扫描完毕后,若p被标记为一个字符串的末尾则说明Tire已经存在,说明s没有被插入。

例题:

题目描述

原题来自:POJ 3630

给定 nnn 个长度不超过 101010 的数字串,问其中是否存在两个数字串 S,TS,TS,T,使得 SSS 是 TTT 的前缀,多组数据。

输入格式

第一行一个整数 TTT,表示数据组数。

对于每组数据,第一行一个数 nnn,接下来 nnn 行输入 nnn 个数字串。

输出格式

对于每组数据,若存在两个数字串 SSS,TTT,使得 SSS 是 TTT 的前缀,则输出 NO ,否则输出 YES 。

请注意此处结果与输出的对应关系!

样例

样例输入

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

样例输出

NO
YES

数据范围与提示

对于 100%100\%100% 的数据,1≤T≤40,1≤n≤1041\le T\le 40, 1\le n \le 10^41≤T≤40,1≤n≤10​4​​。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100100;
const int Z = 15;
int ch[N][Z],tot,T,n;
bool bo[N];
char s[20];

void Init()
{
	memset(ch,0,sizeof(ch));
	memset(bo,false,sizeof(bo));
}

bool it(char *s)
{
	int len=strlen(s),u=1;
	bool fg=false;
	for(int i=0;i<len;i++)
	{
		int c=s[i]-'0';
		if(!ch[u][c]) ch[u][c]=++tot;
		else if(i==len-1) fg=true;
		u=ch[u][c];
		if(bo[u]) fg=true;
	}
	bo[u]=true;
	return fg;
}

int main(void)
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		tot=1;
		Init();
		bool ans=false;
		for(int i=0;i<n;i++)
		{
			scanf("%s",s);
			if(it(s)) ans=true;
		}
		if(ans) printf("NO\n");
		else printf("YES\n");
	}
	return 0; 
}

补充:

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
/*
Tire字典树的存储方法:
构建一个树,每个节点的最多子节点的个数是26(即已知全部单词为小写字母)
1、插入:每次询问一个节点的位置,如果这个位置为空,就为这个位置分配空间,表示此位置存在;
如果此位置已经存在,就沿着这个位置继续查找,直到找到下一个空的位置,重复以上操作;
最后插入完成后统计单词的数量+1; 
2、删除 :从根节点开始,如果查找到空节点,说明这个单词不存在,删除失败(就是不用删除)
如果找到,在最后一个单词的结尾位置单词数量-1,表示删除成功
3查找:从根节点开始, 查找没如果节点位置是空,查找失败,不空,并且找完整个字符串,查找成功,返回YES 
(注意:最后p都是到单词的最后一个字母,并标记那个字母的状态,如果存在那个字母,即最后一个字母表示一整个单词的状态。) 
*/ 
const int maxn = 26;
struct Node{
	int count;
	struct Node* next[maxn];
	Node(int x):count(x)
	{
		for(int i=0;i<maxn;i++)
		next[i]=NULL;
	}
}; 
typedef struct Node* Tire;

void Insert(Tire &t,string str)
{
	int l=str.size(),i,val;
	Tire p=t;
	for(i=0;i<l;i++)
	{
		val=str[i]-'a';
		if(p->next[val]==NULL) p->next[val] = new Node(0); //新建一个节点,表示新节点的存在,即存储了单词; 
		p=p->next[val]; //跳转到下一个字母的位置 
	}
	p->count++; //统计单词个数 
}

void Delete(Tire &t,string str)
{
	int i,l=str.size(),val;
	Tire p=t;
	for(i=0;i<l;i++)
	{
		val=str[i]-'a';
		if(p->next[val]==NULL) return ;
		p=p->next[val];
 	}
 	p->count--;
}

bool Search(Tire &t,string str)
{
	int i,l=str.size(),val;
	Tire p=t;
	for(i=0;i<l;i++)
	{
		val = str[i]-'a';
		if(p->next[val]==NULL) return false;
		p=p->next[val];
	}
	return p->count>0;
}

void print(Tire &t,vector <vector <char> > &vc,vector <char> &word)
{
	Tire p=t;
	if(p==NULL) return ;
	if(p->count) vc.push_back(word);
	for(int i=0;i<26;i++)
	{
		if(t->next[i]!=NULL)
		{
			word.push_back(i+'a');
			print(t->next[i],vc,word);
			word.pop_back();
		}
	}
}

/*
int main() {
    Tire root = new Node(0);
    // 插入
    string strs[] = {"ok","applition","app","apple","apply"};
    for(int i = 0;i < 5;++i){
        Insert(root,strs[i]);
    }//for
    string str("apple");
    cout<<"删除单词["<<str<<"]之前查询结果:"<<endl;
    // 查询
    if(Search(root,str)){
        cout<<"单词["<<str<<"]在字典中"<<endl;
    }//if
    else{
        cout<<"单词["<<str<<"]不在字典中"<<endl;
    }
    cout<<"删除单词["<<str<<"]"<<endl;
    // 删除
    Delete(root,str);
    cout<<"删除单词["<<str<<"]之后查询结果:"<<endl;
    // 查询
    if(Search(root,str)){
        cout<<"单词["<<str<<"]在字典中"<<endl;
    }
    else{
        cout<<"单词["<<str<<"]不在字典中"<<endl;
    }
    // 字典列表
    cout<<"字典列表:"<<endl;
    vector<vector<char> > words;
    vector<char> word;
    print(root,words,word);
    for(int i = 0;i < words.size();++i){
        for(int j = 0;j < words[i].size();++j){
            cout<<words[i][j];
        }//for
        cout<<endl;
    }//for
    return 0;
}
*/

参考文章:https://blog.csdn.net/sunnyyoona/article/details/43900425

猜你喜欢

转载自blog.csdn.net/qq_41829060/article/details/82811499