zoukankan      html  css  js  c++  java
  • 这一篇是对上一篇的修改及注释

      1 void first_set_preprocess(void)//这个函数是用来消除强联通图,把强联通图直接短接,最后生成一个压缩图
      2 {
      3     first_graph_node** rev_first_graph;//这个当作逆转图的入口,因为我们要生成这个逆转图
      4     first_graph_node** new_first_graph;//这个当作原来的图的拷贝,因为在拓扑排序时会毁掉原来的图
      5     pfirst_graph_node temp_first_node,temp_first_add;
      6     pfirst_graph_node temp_pre_node,temp_after_node;,temp_node
      7     int dest_symbol;
      8     int for_i,for_j;
      9     int edge_number;
     10     int* merge_to_list;
     11     int* merge_from_list;//这两个变量是用来合并邻接表使用的
     12     int* already_out_stack;//表示第一遍遍历的时候哪些点已经出栈了
     13     int* already_in_stack;//表示第一遍遍历的时候哪些点在当前栈中
     14     int* already_in_group;//表示哪些点已经在第二次遍历的过程中处理过了
     15     int graph_index;//这个变量用来遍历原来的图
     16     int parent_index;
     17     int* begin_stack;
     18     int* end_stack;
     19     int begin_stack_index;
     20     int end_stack_index;
     21     int current_stack_top;
     22     begin_stack_index=end_stack_index=0;
     23     edge_number=number_edge_first;
     24     rev_first_graph=malloc(sizeof(int)*(node_index+2));
     25     new_first_graph=malloc(sizeof(int)*(node_index+2));
     26     already_in_stack=malloc(sizeof(int)*(node_index+2));
     27     already_out_stack=malloc(sizeof(int)*(node_index+2));
     28     merge_to_list=malloc(sizeof(int)*(node_index+2));
     29     merge_from_list=malloc(sizeof(int)*(node_index+2));
     30     already_in_group=malloc(sizeof(int)*(node_index+2));
     31     for(for_i=1;for_i<node_index+2;for_i++)//这里是为了初始化所有的数组
     32     {
     33         rev_first_graph[for_i]=NULL;
     34         new_first_graph[for_i]=NULL;
     35         parent_set[for_i]=for_i;
     36         merge_to_list[for_i]=0;
     37         merge_from_list[for_i]=0;
     38 
     39     }
     40     for(for_i=1;for_i<node_index+2;for_i++)//生成逆转图
     41     {
     42         temp_first_node=first_graph[for_i];
     43         while(temp_first_node!=NULL)
     44         {
     45             dest_symbol=temp_first_node->first_symbol;
     46             temp_first_add=malloc(sizeof(struct _first_graph_node));
     47             temp_first_add->next=rev_first_graph[dest_symbol];
     48             temp_first_add->first_symbol=for_i;
     49             rev_first_graph[dest_symbol]=temp_first_add;
     50             temp_first_add=malloc(sizeof(struct _first_graph_node));
     51             temp_first_add->first_symbol=dest_symbol;
     52             temp_first_add->next=new_first_next[for_i];
     53             new_first_next[for_i]=temp_first_add;
     54             temp_first_node=temp_first_node->next;
     55         }
     56     }
     57     //两个临时的图都构建完成
     58     //现在开始第一次dfs,为了保留各个节点的结束顺序,我们刚好需要另外的一个栈来保存这些信息
     59     //因此我们需要两个栈 来完成第一次遍历
     60     //第二次遍历则需要哪些点已经完成了汇聚的信息,因此我们需要一个数组来表示哪些点已经完成了汇聚
     61     //同时第二次遍历需要的是深度优先遍历,这次我们可以复用原来的那个栈
     62     while(edge_number>0)
     63     {
     64         for_i=0;
     65         while(new_first_graph[for_i]==NULL)
     66         {
     67             for_i++;
     68         }//找到一个邻接表不为空的点
     69         begin_stack_index=1;
     70         begin_stack[1]=for_i;
     71         //将这个节点压入栈中
     72         already_in_stack[for_i]=1;//标记为已经在栈中
     73         while(begin_stack_index>0)//只要栈中还有点,就一直深搜下去
     74         {
     75             current_stack_top=begin_stack[begin_stack_index]
     76             temp_first_node=new_first_graph[current_stack_top];//获得栈顶的邻接表
     77             if(temp_first_node==NULL)//如果邻接表是空的
     78             {
     79                 if(begin_stack_index!=1)//如果当前栈中有多余一个元素
     80                 {
     81                     end_stack_index++;
     82                     end_stack[end_stack_index]=current_stack_top;
     83                     already_out_stack[current_stack_top]=1;
     84                     already_in_stack[current_stack_top]=0;
     85                     begin_stack_index--;
     86                     
     87                     //将这个点弹出当前栈,并进入另外一个栈,
     88                 }
     89                 else//如果只有一个元素,直接出栈就行了
     90                 {
     91                     already_in_stack[current_stack_top]=0;
     92                     begin_stack_index--;
     93                 }
     94             }
     95             else//如果邻接表不是空的
     96             {
     97                 dest_symbol=temp_first_node->first_symbol;
     98                 if(already_out_stack[dest_symbol]!=1)//如果邻接表中第一个节点还未处理完
     99                 {
    100                     if(already_in_stack[dest_symbol]!=1)//如果这个点还没加入栈中,则直接入栈
    101                     {
    102                         begin_stack_index++;
    103                         begin_stack[begin_stack_index]=dest_symbol;
    104                         already_in_stack[dest_symbol]=1;
    105                     }
    106                 //如果已经加入栈中,则不需要入栈,直接忽略掉
    107                     //不过有一点需要注意的就是要在当前邻接表中删除这个节点,以防下次重复添加
    108                 new_first_graph[current_stack_top]=temp_first_node->next;
    109                 edge_number--;
    110                 free(temp_first_node);
    111             }
    112         }
    113 
    114 
    115 
    116 
    117         }
    118     }//现在全都按照结束序进入了第二个栈中
    119     //现在开始第二遍深度优先遍历,不过跟前面的那次遍历有点不同。。。
    120     //因为这次有了集合操作
    121     while(end_stack_index>0)//只要栈里还有元素
    122     {
    123         current_stack_top=end_stack[end_stack_index];
    124         end_stack_index--;//取栈顶元素
    125         if(already_in_group[current_stack_top]!=1)
    126             //如果栈顶元素已经被汇聚成为了一个群,则不需要处理,否则需要处理
    127         {
    128             begin_stack_index=1;
    129             begin_stack[begin_stack_index]=current_stack_top;//栈顶元素入栈
    130             while(rev_first_graph[begin_stack[begin_stack_index]]!=NULL)
    131                 //只要栈顶元素的邻接表没有空,即要么还在汇聚,要么还有边
    132             {
    133                 temp_node=rev_first_graph[begin_stack[begin_stack_index]];
    134                 dest_symbol=temp_node->first_symbol;//我们就对栈顶的元素进行dfs
    135                 if(already_in_group[dest_symbol]!=1)//如果栈顶元素的邻接表的第一个元素还没处理完
    136                 {
    137                     if(already_in_stack[dest_symbol]!=1)//如果这个元素不在当前栈中
    138                     {
    139                         begin_stack_index++;
    140                         begin_stack[begin_stack_index]=dest_symbol;
    141                         already_in_stack[dest_symbol]=1;
    142                         //直接入栈,并设置相应的位
    143                     }
    144                     else//如果已经在栈中,则需要汇聚了,这里实现的有点丑陋,可以改进
    145                     {
    146                         parent_index=parent_set[dest_symbol];//找到所在群的代表节点
    147                         while(begin_stack[begin_stack_index]!=parent_index)//处理所有的在当前环中的节点
    148                         {
    149                             //这里开始合并操作
    150                             for(for_i=0;for_i<node_index+2;for_i++)
    151                             {
    152                                 merge_to_list[for_i]=0;
    153                                 merge_from_list[for_i]=0;
    154                             }//初始化邻接矩阵,这个矩阵用来记录这两个点的指向其他点的边
    155 
    156                             current_stack_top=begin_stack[begin_stack_index];
    157                             already_in_group[current_stack_top]=1;//把这个点设置为已经被汇聚了
    158                             temp_after_node=rev_first_graph[current_stack_top];
    159                             temp_pre_node=NULL;
    160                             //这里开始删除边了
    161                             //下面把这两个边里面邻接表中互相连接的边删除,并减少边的数目
    162                             //之后再把两者的邻接表合并,碰到重复的边也删除一个,并减少边的数目
    163                             
    164                             while(temp_after_node!=NULL)//由于这个节点在汇聚之后将不再使用,因此全部删除
    165                             {
    166                                 if(parent_set[temp_after_node->first_symbol]!=parent_index)//对于还有用的边需要做记录
    167                                 {
    168                                     merge_from_list[temp_after_node->first_symbol]=1;
    169                                     temp_pre_node=temp_after_node;
    170                                     temp_after_node=temp_after_node->next;
    171                                 }
    172                                 rev_first_graph[current_stack_top]->next=temp_after_node->next;
    173                                 free(temp_after_node);
    174                                 temp_after_node=rev_first_graph[current_stack_top];
    175                             }
    176                             temp_after_node=rev_first_graph[parent_index];
    177                             temp_pre_node=NULL;
    178                             while(temp_after_node!=NULL)//删除两个节点中互相指的边
    179                             {
    180                                 if(parent_set[temp_after_node->first_symbol]==current_stack_top)//如果是无用边,则删除
    181                                 {
    182                                     if(temp_pre_node==NULL)//这里需要考虑是不是第一个节点
    183                                     {
    184                                         rev_first_graph[current_graph_top]=temp_after_node->next;
    185                                         free(temp_after_node);
    186                                         temp_after_node=rev_first_graph[current_graph_top];
    187                                         edge_number--;
    188                                     }
    189                                     else
    190                                     {
    191                                         temp_pre_node->next=temp_after_node->next;
    192                                         free(temp_after_node);
    193                                         temp_after_node=temp_pre_node->next;
    194                                         edge_number--;
    195                                     }
    196                                 }
    197                                 else//如果是无用边,则遍历下一个节点
    198                                 {
    199                                     merge_to_list[temp_after_node->first_symbol]=1;
    200                                     temp_pre_node=temp_after_node;
    201                                     temp_after_node=temp_after_node->next;
    202                                 }
    203                             }
    204                             for(for_i=1;for_i<node_index;for_i++)
    205                             {
    206                                 if(merge_to_list[for_i]==1)
    207                                 {
    208                                     if(merge_from_list[for_i]==1)
    209                                     {
    210                                         edge_number--;
    211                                     }
    212                                     else
    213                                     {
    214                                         temp_first_node_add=malloc(sizeof(strcut _first_graph_node));
    215                                         temp_first_node_add->first_symbol=for_i;
    216                                         temp_first_node_add->next=rev_first_graph[parent_index];
    217                                         rev_first_graph[parent_index]=temp_first_node_add;
    218                                         merge_to_list[for_i]=1;
    219                                     }
    220                                 }
    221                             }//边合并完成
    222                             //至此,邻接表合并完成
    223                             //然后修改位置数组
    224                             for(for_i=1;for_i<node_index+1;for_i++)
    225                             {
    226                                 if(parent_set[for_i]==current_stack_top)
    227                                 {
    228                                     parent_set[for_i]=parent_index;
    229                                 }
    230                             }//所属的群索引标记完成
    231                             begin_stack_index--;//然后考虑下一个节点,
    232                         }
    233                     }
    234                 }
    235                 else//如果栈顶元素的邻接表的第一个元素已经被处理完了
    236                 {
    237                     //则需要从当前邻接表中摘除这个点
    238                     rev_first_graph[begin_stack[begin_stack_index]]=temp_node->next;
    239                     free(temp_node);
    240                     //释放空间
    241                 }
    242             }//当前栈底可达的点都已经被合并为一个群了
    243             already_in_group[begin_stack[1]]=1;//设置为当前栈底已经被汇聚了
    244         }
    245         else
    246         {
    247             //因为这个点已经被汇聚过了,因此什么都不干
    248         }
    249     }//所有的群都已经生成完毕了
    250     //汇聚完成
    251 }
  • 相关阅读:
    mac sourceTree 每次操作提示需要密码
    docker-compose.yml开机启动
    详解Oracle 21c 中的只读Oracle主⽬录特性 (ROOH)
    使用kubeadm一键部署kubernetes集群
    Ubuntu18.04 开机自启动(需要 sudo 权限)
    nginx加载vue3 打包后的静态文件
    使用Docker搭建Nextcloud SSL站点
    Docker+Selenium+TestNG+Maven+Jenkins环境搭建
    Windows Server 2016安装AD并开启SSL
    Centos 环境配置内网 Yum 源
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3175519.html
Copyright © 2011-2022 走看看