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 }