由于在生成前后缀的时候,我们需要将这个文法符号按照拓扑排序来排列生成顺序,不过当语法里面有环的时候,一般的拓扑排序就无效了,这个时候需要采取将一个强联通区域的点汇聚在一起,也就是生成压缩图。课本上虽说强连通算法是线性时间,但是不写不知道,一写吓一跳,尼玛都快四次复杂度了有木有。
这里就贴一下生成强连通的代码
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 already_in_stack[for_i]=1; 72 while(begin_stack_index>0) 73 { 74 current_stack_top=begin_stack[begin_stack_index] 75 temp_first_node=new_first_graph[current_stack_top]; 76 if(temp_first_node==NULL) 77 { 78 if(begin_stack_index!=1) 79 { 80 end_stack_index++; 81 end_stack[end_stack_index]=current_stack_top; 82 already_out_stack[current_stack_top]=1; 83 already_in_stack[current_stack_top]=0; 84 begin_stack_index--; 85 } 86 else 87 { 88 already_in_stack[current_stack_top]=0; 89 begin_stack_index--; 90 } 91 } 92 else 93 { 94 dest_symbol=temp_first_node->first_symbol; 95 if(already_out_stack[dest_symbol]!=1) 96 { 97 if(already_in_stack[dest_symbol]!=1) 98 { 99 begin_stack_index++; 100 begin_stack[begin_stack_index]=dest_symbol; 101 already_in_stack[dest_symbol]=1; 102 } 103 104 } 105 new_first_graph[current_stack_top]=temp_first_node->next; 106 edge_number--; 107 free(temp_first_node); 108 } 109 } 110 111 112 113 114 }//现在全都按照结束序进入了第二个栈中 115 //现在开始第二遍深度优先遍历,不过跟前面的那次遍历有点不同。。。 116 //因为这次有了集合操作 117 while(end_stack_index>0)//只要栈里还有元素 118 { 119 current_stack_top=end_stack[end_stack_index]; 120 end_stack_index--; 121 if(already_in_group[current_stack_top]!=1) 122 { 123 begin_stack_index=1; 124 begin_stack[begin_stack_index]=current_stack_top; 125 while(rev_first_graph[begin_stack[1]]!=NULL) 126 { 127 temp_node=rev_first_graph[begin_stack[begin_stack_index]]; 128 dest_symbol=temp_node->first_symbol; 129 if(already_in_group[dest_symbol]!=1) 130 { 131 if(already_in_stack[dest_symbol]!=1) 132 { 133 begin_stack_index++; 134 begin_stack[begin_stack_index]=dest_symbol; 135 already_in_stack[dest_symbol]=1; 136 } 137 else 138 { 139 parent_index=parent_set[dest_symbol];//找到所在群的代表节点 140 while(begin_stack[begin_stack_index]!=parent_index) 141 { 142 //这里开始合并操作 143 current_stack_top=begin_stack[begin_stack_index]; 144 temp_after_node=rev_first_graph[current_stack_top]; 145 temp_pre_node=NULL; 146 //这里开始删除边了 147 //下面把这两个边里面邻接表中互相连接的边删除,并减少边的数目 148 //之后再把两者的邻接表合并,碰到重复的边也删除一个,并减少边的数目 149 for(for_i=0;for_i<node_index+2;for_i++) 150 { 151 merge_to_list[for_i]=0; 152 merge_from_list[for_i]=0; 153 } 154 while(temp_after_node!=NULL) 155 { 156 if(parent_set[temp_after_node->first_symbol]==parent_index) 157 { 158 if(temp_pre_node==NULL) 159 { 160 rev_first_graph[current_graph_top]=temp_after_node->next; 161 free(temp_after_node); 162 temp_after_node=rev_first_graph[current_graph_top]; 163 edge_number--; 164 } 165 else 166 { 167 temp_pre_node->next=temp_after_node->next; 168 free(temp_after_node); 169 temp_after_node=temp_pre_node->next; 170 edge_number--; 171 } 172 } 173 else 174 { 175 merge_from_list[temp_after_node->first_symbol]=1; 176 temp_pre_node=temp_after_node; 177 temp_after_node=temp_after_node->next; 178 } 179 } 180 temp_after_node=rev_first_graph[parent_index]; 181 temp_pre_node=NULL; 182 while(temp_after_node!=NULL) 183 { 184 if(parent_set[temp_after_node->first_symbol]==current_stack_top) 185 { 186 if(temp_pre_node==NULL) 187 { 188 rev_first_graph[current_graph_top]=temp_after_node->next; 189 free(temp_after_node); 190 temp_after_node=rev_first_graph[current_graph_top]; 191 edge_number--; 192 } 193 else 194 { 195 temp_pre_node->next=temp_after_node->next; 196 free(temp_after_node); 197 temp_after_node=temp_pre_node->next; 198 edge_number--; 199 } 200 } 201 else 202 { 203 merge_to_list[temp_after_node->first_symbol]=1; 204 temp_pre_node=temp_after_node; 205 temp_after_node=temp_after_node->next; 206 } 207 } 208 for(for_i=1;for_i<node_index;for_i++) 209 { 210 if(merge_to_list[for_i]==1) 211 { 212 if(merge_from_list[for_i]==1) 213 { 214 edge_number--; 215 } 216 else 217 { 218 temp_first_node_add=malloc(sizeof(strcut _first_graph_node)); 219 temp_first_node_add->first_symbol=for_i; 220 temp_first_node_add->next=rev_first_graph[parent_index]; 221 rev_first_graph[parent_index]=temp_first_node_add; 222 merge_to_list[for_i]=1; 223 } 224 } 225 }//边合并完成 226 //至此,邻接表合并完成 227 //然后修改位置数组 228 for(for_i=1;for_i<node_index+1;for_i++) 229 { 230 if(parent_set[for_i]==current_stack_top) 231 { 232 parent_set[for_i]=parent_index; 233 } 234 }//所属的群索引标记完成 235 begin_stack_index--; 236 } 237 } 238 } 239 else 240 { 241 begin_stack_index++; 242 begin_stack[begin_stack_index]=dest_symbol; 243 } 244 }//当前栈底可达的点都已经被合并为一个群了 245 already_in_group[begin_stack[1]]=1; 246 } 247 else 248 { 249 //神马都不干 250 } 251 }//所有的群都已经生成完毕了 252 }