当前位置:   article > 正文

第二章 数据结构 (二)(并查集、Trie树)

第二章 数据结构 (二)(并查集、Trie树)

一、Trie树(用来高效存储和查找字符串集合的数据结构)

1、 用二维数组来构建一个树,第一维为结点下标,第二维为子节点,单个二维数组的值为子节点下标。构建字典树用于查询和插入。

  1. #include<bits/stdc++.h>
  2. //835 存储查询字符串
  3. using namespace std;
  4. const int N=1e5+10;
  5. int son[N][26],cnt[N],idx;
  6. char str[N];
  7. //下标是0的节点既是根节点,又是空节点
  8. //son数组第一维为父节点的下标,第二维度为某一个儿子的字母,其值为其这个儿子的下标
  9. void insert(char str[])
  10. {
  11. int p=0;//都是从0号位置开始
  12. for(int i=0;str[i];i++)
  13. {
  14. int u=str[i]-'a';//儿子映射为数字
  15. if(!son[p][u]) son[p][u]=++idx;
  16. //为父节点添加儿子
  17. p=son[p][u];
  18. //更新父节点
  19. }
  20. cnt[p]++;//最后一个p即为一个字符串的尾结点,记录这个结点出现的次数
  21. }
  22. int query(char str[])
  23. {
  24. int p=0;
  25. for(int i=0;str[i];i++)
  26. {
  27. int u=str[i]-'a';
  28. if(!son[p][u])return 0;
  29. p=son[p][u];
  30. }
  31. return cnt[p];
  32. }
  33. int main()
  34. {
  35. int n;
  36. scanf("%d",&n);
  37. for(int i=0;i<n;i++)
  38. {
  39. char op[2];
  40. scanf("%s%s",op,str);
  41. //两个字符串输入的时候中间要有空格
  42. if(*op=='I')insert(str);
  43. else cout<<query(str)<<endl;
  44. }
  45. }

二、并查集

1、并查集可以非常快速地执行将两个集合合并,或询问两个元素是否在同一个集合中两个操作

 优化:路径压缩优化

2、实现

  1. #include<bits/stdc++.h>
  2. //836 并查集 集合合并和判断
  3. using namespace std;
  4. const int N=1e5+10;
  5. int p[N];//存父节点编号
  6. int n,m;
  7. int find(int x)//返回祖宗结点
  8. {
  9. //递归求解
  10. if(p[x]!=x)p[x]=find(p[x]);
  11. return p[x];//递归终止条件
  12. }
  13. int main()
  14. {
  15. cin>>n>>m;
  16. for(int i=0;i<n;i++)p[i]=i;
  17. while(m--)
  18. {
  19. char op[2];//char不会忽略字符和回车,读字符串会忽略字符和回车
  20. int a,b;
  21. cin>>op>>a>>b;//两种输入方式都可以
  22. //scanf("%s%d%d",op,&a,&b);
  23. if(op[0]=='M')p[find(a)]=find(b);//合并两个集合
  24. else
  25. {
  26. if(find(a)==find(b))puts("Yes");
  27. else puts("No");
  28. }
  29. }
  30. }

3、并查集例题计算连通块中的点的数量以及合并连通块

维护一个size数组,只有根结点有效,初始化为1,每次合并两个树的时候,更新size。

  1. #include<bits/stdc++.h>
  2. //837 连通块中点的数量
  3. using namespace std;
  4. const int N=1e5+10;
  5. int p[N];//存父节点编号
  6. int n,m;
  7. int size[N];//连通块中点的数量
  8. //只有根结点中的size是有意义的
  9. int find(int x)//返回祖宗结点
  10. {
  11. //递归求解
  12. if(p[x]!=x)p[x]=find(p[x]);
  13. return p[x];//递归终止条件
  14. }
  15. int main()
  16. {
  17. cin>>n>>m;
  18. for(int i=0;i<n;i++)p[i]=i,size[i]=1;
  19. while(m--)
  20. {
  21. char op[2];//char不会忽略字符和回车,读字符串会忽略字符和回车
  22. int a,b;
  23. cin>>op;//两种输入方式都可以
  24. if(op[0]=='C')
  25. {
  26. scanf("%d%d",&a,&b);
  27. if(find(a)==find(b))continue;
  28. //当要结合的两个点已经在同一个集合里面
  29. //下面不能再在size上加数了
  30. size[find(b)]+=size[find(a)];
  31. //先更新size
  32. p[find(a)]=find(b);
  33. }
  34. else if(op[1]=='1')
  35. {
  36. scanf("%d%d",&a,&b);
  37. if(find(a)==find(b))puts("Yes");
  38. else puts("No");
  39. }
  40. else
  41. {
  42. cin>>a;
  43. cout<<size[find(a)]<<endl;
  44. }
  45. }
  46. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52811
推荐阅读
相关标签
  

闽ICP备14008679号