第二章 数据结构 (二)(并查集、Trie树)
一、Trie树(用来高效存储和查找字符串集合的数据结构)
1、 用二维数组来构建一个树,第一维为结点下标,第二维为子节点,单个二维数组的值为子节点下标。构建字典树用于查询和插入。
#include<bits/stdc++.h>
//835 存储查询字符串
using namespace std;
const int N=1e5+10;
int son[N][26],cnt[N],idx;
char str[N];
//下标是0的节点既是根节点,又是空节点
//son数组第一维为父节点的下标,第二维度为某一个儿子的字母,其值为其这个儿子的下标
void insert(char str[])
{
int p=0;//都是从0号位置开始
for(int i=0;str[i];i++)
{
int u=str[i]-'a';//儿子映射为数字
if(!son[p][u]) son[p][u]=++idx;
//为父节点添加儿子
p=son[p][u];
//更新父节点
}
cnt[p]++;//最后一个p即为一个字符串的尾结点,记录这个结点出现的次数
}
int query(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'a';
if(!son[p][u])return 0;
p=son[p][u];
}
return cnt[p];
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
char op[2];
scanf("%s%s",op,str);
//两个字符串输入的时候中间要有空格
if(*op=='I')insert(str);
else cout<<query(str)<<endl;
}
}
二、并查集
1、并查集可以非常快速地执行将两个集合合并,或询问两个元素是否在同一个集合中两个操作
优化:路径压缩优化
2、实现
#include<bits/stdc++.h>
//836 并查集 集合合并和判断
using namespace std;
const int N=1e5+10;
int p[N];//存父节点编号
int n,m;
int find(int x)//返回祖宗结点
{
//递归求解
if(p[x]!=x)p[x]=find(p[x]);
return p[x];//递归终止条件
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)p[i]=i;
while(m--)
{
char op[2];//char不会忽略字符和回车,读字符串会忽略字符和回车
int a,b;
cin>>op>>a>>b;//两种输入方式都可以
//scanf("%s%d%d",op,&a,&b);
if(op[0]=='M')p[find(a)]=find(b);//合并两个集合
else
{
if(find(a)==find(b))puts("Yes");
else puts("No");
}
}
}
3、并查集例题计算连通块中的点的数量以及合并连通块
维护一个size数组,只有根结点有效,初始化为1,每次合并两个树的时候,更新size。
#include<bits/stdc++.h>
//837 连通块中点的数量
using namespace std;
const int N=1e5+10;
int p[N];//存父节点编号
int n,m;
int size[N];//连通块中点的数量
//只有根结点中的size是有意义的
int find(int x)//返回祖宗结点
{
//递归求解
if(p[x]!=x)p[x]=find(p[x]);
return p[x];//递归终止条件
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)p[i]=i,size[i]=1;
while(m--)
{
char op[2];//char不会忽略字符和回车,读字符串会忽略字符和回车
int a,b;
cin>>op;//两种输入方式都可以
if(op[0]=='C')
{
scanf("%d%d",&a,&b);
if(find(a)==find(b))continue;
//当要结合的两个点已经在同一个集合里面
//下面不能再在size上加数了
size[find(b)]+=size[find(a)];
//先更新size
p[find(a)]=find(b);
}
else if(op[1]=='1')
{
scanf("%d%d",&a,&b);
if(find(a)==find(b))puts("Yes");
else puts("No");
}
else
{
cin>>a;
cout<<size[find(a)]<<endl;
}
}
}