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 }