字符串集合的合并

将多个集合合并成没有交集的集合。      给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。    

 (1)请描述你解决这个问题的思路;   

 (2)请给出主要的处理流程,算法,以及算法的复杂度    

 (3)请描述可能的改进。  采用并查集。

  首先所有的字符串都在单独的并查集中。然后依扫描每个集合,顺序合并将两个相邻元素合并。例如,对于,首先查看aaa和bbb是否在同一个并查集中,如果不在,那么把它们所在的并查集合并,然后再看bbb和ccc是否在同一个并查集中,如果不在,那么也把 它们所在的并查集合并。接下来再扫描其他的集合,当所有的集合都扫描完了,并查集代表的集合便是所求。复杂度应该是O(NlgN)的。改进的话,首先可以 记录每个节点的根结点,改进查询。合并的时候,可以把大的和小的进行合,这样也减少复杂度。

#include <stdio.h>
#include <stdlib.h>

#define MAX 26

//将给定的字符串的集合转化为如下的关系“aaa”编号为1,以此类推。。。。 
int relation[6][2] = {
        {1,2},//{"aaa","bbb"}
        {1,3},//{"aaa","ccc"}
        {2,4},
        {5,6},
        {4,8},
        {7,7}//{ggg}
      };
//(之所以这么复杂去实现,主要是为了输出ggg,目前使用并查集没有更好的办法) 
//找主根(一开始初始化为-1,如果A[x]<0,首先
//给其根节点赋值为本身并返回,其次其根节点为本身的,返回其本身。)
//此函数主要目的是在集合合并处使用           
int find_root(int A[], int x)
{
//结合调用的for循环i=0~6;故只有出现的字母才会出现自己的根节点是自己,没有出现的字母根节点仍然是-1;(为了以后再输出时方便,加以控制)    
  if(A[x]<0)
      {
          A[x]=x;
        return x;
    }
  else if(A[x]==x)
          return x;
  else
    return find_root(A, A[x]); 
}
//(此函数主要是在最后结果输出时使用 ) 
//返回根节点 
int findroot(int A[],int x)
{
  if(A[x]==x||A[x]==-1)
    return A[x];
  else
    return findroot(A, A[x]); 
}

int main(int argc, char *argv[])
{
  int i;
  int root1;
  int root2;
  int A[MAX];//根节点的存储 
//一开始根节点的数组里面的值初始化为-1 
  for(i=0;i<26;i++)
    A[i] = -1;
//遍历relation二维数组来实现集合的合并   
  for(i=0;i<6;i++)
   {
    root1 = find_root(A, relation[i][0]); 
    root2 = find_root(A, relation[i][1]);
    if(root1!=root2)//集合根节点的合并 (此处还可以优化?) 
            A[root1]=root2;
   } 
   
//结果的输出  
   int flag[26]={0};
   for(i=1;i<26;i++)
   {
           if(flag[i])
               continue;
           int mark=findroot(A,i);//为了输出找根节点  之前是A[i]  by felix
        //根节点为-1的不考虑 
           if(mark!=-1)
           {
               flag[i]=1;
               printf("%c%c%c\t",i+'a'-1,i+'a'-1,i+'a'-1);
               for(int j=i+1;j<26;j++)
               {
                   if(flag[j])
                       continue;
                   int marks=findroot(A,A[j]);
                   if(marks==mark)
                   {
                       flag[j]=1;
                       printf("%c%c%c\t",j+'a'-1,j+'a'-1,j+'a'-1);
                }
            }
            puts("");
        }
        
   }
  system("PAUSE");    
  return 0;
}
转载:https://www.cnblogs.com/wft1990/p/6984710.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值