一、基础知识:
树状结构保存字符串,查找快,判断前缀快,保存数量大。
建Trie树:
逐一把每则单词的每个字母插入Trie。插入前先看前缀是否存在。如果存在,就共享,否则创建对应的节点和边
struct Trie
{
int num;
Trie *nx[N];
};
num记录该前缀出现的次数,N是分支数,比如小写字母构成的单词的树N就是26,十进制的数字N就是10,二进制的01编码N就是2
具体建树代码:
Trie *root;
void init (Trie *t)
{
for (int j = 0; j < N; ++j) //初始化
{
t->nx[j] = NULL;
}
t->num = 0;
}
void Insert (char str[])//插入单词
{
Trie *p = root;
int len = strlen (str);
for (int i = 0; i < len; ++i)
{
int id = str[i] - 'a';
if (p->nx[id] == NULL)
{
Trie *t = new Trie;
init(t);
p->nx[id] = t;
}
p = p->nx[id];
p->num++;
}
}
查询:
查询非常简单。比如要查找的单词是int,顺着路径i -> in -> int就找到了。遇到NULL就是没有return 0;就好
int Find(char str[])//查找前缀为str的单词数
{
Trie *p = root;
int cnt,len = strlen(str);
for (int i = 0;i < len;++i)
{
int id = str[i] - 'a';
if (p->nx[id] == NULL) return 0;
p = p->nx[id];
cnt = p->num;
}
return cnt;
}
释放:
另外关于内存的释放,貌似大多数题不写释放都能A
void Delete(Trie *t)
{
for (int i = 0;i < N;++i)
{
if (t->nx[i]!=NULL) Delete(t->nx[i]);
}
delete t;
}
测试:
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 26;
struct Trie_Tree
{
struct Trie
{
int num; //前缀数
Trie *nx[N];//分支
} ;
Trie *root;
void init(Trie *t) //初始化节点
{
for (int i = 0;i < N;++i)
{
t->nx[i] = NULL;
}
t->num = 0;
}
void build()//初始化根
{
root = new Trie;
init(root);
}
void Insert(char word[]) //初始化单词
{
Trie *p = root;
int len = strlen(word);
for (int i = 0;i < len;++i)
{
int id = word[i] - 'a';//小写字母的单词就-'a'
if (p->nx[id] == NULL) //没有就新建一个
{
Trie *t = new Trie;
init(t);
p->nx[id] = t;//建
}
p = p->nx[id];//往下走
p->num++;
}
}
int Find(char word[]) //查找前缀为word的单词数
{
Trie *p = root;;
int cnt,len = strlen(word);
for (int i = 0;i < len;++i)
{
int id = word[i] - 'a';
if (p->nx[id] == NULL) return 0;//没有这样的前缀
p = p->nx[id];
cnt = p->num;//其实cnt是最后一个字母的num
}
return cnt;
}
void Delete(Trie *t)
{
for (int i = 0;i < N;++i)
{
if (t->nx[i]!=NULL) Delete(t->nx[i]);
}
delete t;
}
}text;
int main()
{
/******************************************************
测试:
1.建立一个n个单词的字典树
2.对输入的m个前缀查找在字典树中出现的次数
******************************************************/
text.build();
int n,m;cin>>n>>m;
char s[222];
for (int i = 1;i <= n;++i)
{
scanf("%s",s);
text.Insert(s);
}
for (int i = 1;i <= m;++i)
{
scanf("%s",s);
int t = text.Find(s);
if (t)
{
printf("%s shows %d times in the Trie \n",s,t);
}
else printf("%s does not exist in the Trie \n",s);
}
text.Delete(text.root);
return 0;
}
运行结果:
二、入门题目:
最基础的模板,求前缀串在Trie中出现的次数,直接建完树查询
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<stdlib.h>
#include<cctype>
#include<string>
using namespace std;
typedef long long ll;
#define Pintl(x) printf("%d\n",x)
const int N = 26;
struct Trie
{
int num;
Trie* nx[N];
};
Trie *root;
void init (Trie *t)
{
for (int j = 0; j < N; ++j) //初始化