这一篇是对上一篇的修改及注释

  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 }

 

posted @ 2013-07-06 20:49  huangnima  阅读(259)  评论(0编辑  收藏  举报