zoukankan      html  css  js  c++  java
  • 字符串集合的合并

    将多个集合合并成没有交集的集合。    
    给定一个字符串的集合,格式如:{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	",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	",j+'a'-1,j+'a'-1,j+'a'-1);
                    }
                }
                puts("");
            }
            
       }
      system("PAUSE");    
      return 0;
    }

     方法二:使用hash_table方法

    http://www.cnblogs.com/ttltry-air/archive/2012/08/14/2638437.html

  • 相关阅读:
    2015531 网络攻防 Exp1 PC平台逆向破解(5)M
    2017-2018-1 20155331 嵌入式C语言
    20155330 《网络对抗》 Exp9 web安全基础实践
    20155330 《网络对抗》 Exp8 Web基础
    20155330 《网络对抗》 Exp7 网络欺诈防范
    20155330 《网络对抗》 Exp6 信息搜集与漏洞扫描
    20155330 《网络对抗》 Exp5 MSF基础应用
    20155330 《网络攻防》 Exp4 恶意代码分析
    20155330 《网络攻防》 Exp3 免杀原理与实践
    20155330 《网络对抗》 Exp2 后门原理与实践
  • 原文地址:https://www.cnblogs.com/wft1990/p/6984710.html
Copyright © 2011-2022 走看看