输入形如:
1 7
6 8 3
9 6
8 2
2 5
5 8
3 9
7 9 4
4 1
import java.io.BufferedReader;
import java.io.FileNotFoundException;import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
//由于个人比较懒,输入的起始点必须是edge集文件中的第一个条目
class Stack2 {
String [] point;
//int [] label;
String [] order;
int stackEnd;
int count;
int orderPointer;
Stack2(int length) {
this.point = new String [length];
//this.label = new int [length];
this.order = new String [length];
this.stackEnd = -1;
this.count = length;
this.orderPointer = 0;
}
void addVertex(String s) {
stackEnd++;
this.point[this.stackEnd] = s;
System.out.println("Add to point: " + s);
}
void popVertex() {
if(stackEnd == 0) {
System.out.println("SpoilOver!");
return;
}
stackEnd--;
}
void addOrder(String s) {
this.order[this.orderPointer] = s;
this.orderPointer++;
System.out.println("Add to order: " + s);
}
boolean pointContainsOrNot(String s) {
boolean flags = false;
for(int k=0; k<=this.stackEnd; k++) {
if(this.point[k].equals(s)) {
flags = true;
break;
}
}
return flags;
}
public class week4_DFS_TowPassMethodGetSCC {
/**1、第一次DFS(),得出sinkVertexs
* 2、得到边集V的取反集V‘
* 3、从sinkVertexs依次取点,执行DFS_Loop(),每次输出的点就属于同一个SCC
*/
public static ArrayList<String []> edge_Of_firstLoop = new ArrayList<String []> ();
//存放第一次loop的边集V
public static ArrayList<String> seq_Of_edge = new ArrayList<String> ();
//seq_Of_edge存放所有边集的起点,用于标定edge_Of_firstLoop各个边的位置。
public static ArrayList<String> vertex_state = new ArrayList<String> ();
//存放第一次loop中还未成为sink vertex的点
public static ArrayList<String> vertex_explored_state = new ArrayList<String> ();
//第一次loop中点是否被explored
public static ArrayList<String []> edge_Of_SecondLoop = new ArrayList<String []> ();
//存放第一次loop的边集V
public static ArrayList<String> sinkVertexs = new ArrayList<String> ();
//按照执行二次loop所需的顺序存放各个节点。第二次loop时,它的作用相当于vertex_state在第一次loop中的作用。
//用于存放找到的所有强连通图
public static Stack2 vertexStack;
public static String startVertex;
public static String sVertex;
public static int current_edge_seq = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
FileReader fr = new FileReader("E:/toposort.txt");
BufferedReader br = new BufferedReader(fr);
String s;
int num = 0;
while((s = br.readLine())!= null) {
String k;
edge_Of_firstLoop.add(s.split(" "));
k = edge_Of_firstLoop.get(edge_Of_firstLoop.size()-1)[0];
vertex_state.add(k);
seq_Of_edge.add(k);
num++;
vertex_explored_state.add(Integer.toString(num));
}
br.close();
String wlgq = getStartVertex();
sVertex = wlgq;
startVertex = wlgq;
vertexStack = new Stack2(edge_Of_firstLoop.size());
while(vertex_state.size() != 0) {
int leftNum = edge_Of_firstLoop.size()-vertex_state.size()-1;
if(leftNum != -1 && vertexStack.order[leftNum].equals(sVertex)){
startVertex = vertex_state.get(vertex_state.size()-1);
current_edge_seq = getCurrentEdgeSeq(startVertex);
sVertex = startVertex;
}
DFS();
}
System.out.println("-----------------------------DFS_firstloop is gone!----------------------------");
//首先将vertex_explored_state中所有点恢复为未explored状态
for(int i=1; i<=vertex_explored_state.size(); i++) {
vertex_explored_state.set(i-1, Integer.toString(i));
}
current_edge_seq = sinkVertexs.size()-1;
startVertex = sinkVertexs.get(current_edge_seq);
vertexStack.stackEnd = -1;
vertexStack.orderPointer = 0;
int scc_seq = 1;
while(sinkVertexs.size() != 0) {
int leftNum = edge_Of_SecondLoop.size()-sinkVertexs.size()-1;
if(leftNum != -1 && vertexStack.order[leftNum].equals(sVertex)) {
startVertex = sinkVertexs.get(sinkVertexs.size()-1);
current_edge_seq = getCurrentEdgeSeq_SecondLoop(startVertex);
sVertex = startVertex;
scc_seq++;
}
DFS_Loop(scc_seq);
}
}catch(FileNotFoundException fnfe) {
fnfe.printStackTrace();
}catch(IOException ie) {
ie.printStackTrace();
}
}
public static void DFS_Loop(int scc_seq) {
//sinkVertexs每次向vertexStack.point增加末尾的点后,就remove该点
String [] temp = edge_Of_SecondLoop.get(current_edge_seq);
vertex_explored_state.set(Integer.parseInt(temp[0])-1, "-1");
//当temp[0]不在point[ ]中时,将其添加到point
if(!vertexStack.pointContainsOrNot(temp[0])) {
vertexStack.addVertex(temp[0]);
}
//如果点A对应的边集为空,那么它一定是一个sink vertex。
if(temp.length == 1) {
System.out.println(temp[0] + " is a lonely( and sink) vertex!");
vertexStack.addOrder(temp[0]);
sinkVertexs.remove(temp[0]);
vertexStack.popVertex();
current_edge_seq = getCurrentEdgeSeq_SecondLoop(vertexStack.point[vertexStack.stackEnd]);
return;
}
//对指定的边集edge[startVertex]进行探索
for(int j=1; j<temp.length; j++) {
//遇到未探索的点时,将其作为startVertex
if(sinkVertexs.contains(temp[j]) && !vertex_explored_state.get(Integer.parseInt(temp[j])-1).equals("-1")) {
startVertex = temp[j];
//father_edge_seq = current_edge_seq;
current_edge_seq = getCurrentEdgeSeq_SecondLoop(startVertex);
//current_edge_seq = seq_Of_edge.indexOf(vertexStack.point[vertexStack.stackEnd]);
//vertex_state.remove(temp[j]);
//vertexStack.addVertex(temp[j]);
return;
}
//edge[startVertex]读取到最后一个点时,这个点也被explore过,那么startVertex点就是个sink点
if(j == temp.length-1 && vertex_explored_state.get(Integer.parseInt(temp[j])-1).equals("-1")) {
System.out.println(temp[0] + " belongs to scc[" + scc_seq + "]");
vertexStack.addOrder(temp[0]);
vertexStack.popVertex();
sinkVertexs.remove(temp[0]);
current_edge_seq = getCurrentEdgeSeq_SecondLoop(vertexStack.point[vertexStack.stackEnd]);
return;
}
}
}
public static void DFS() {
//对于含startVertex的每个edge[startVertex]
/**
*/
String [] temp = edge_Of_firstLoop.get(current_edge_seq);
//String [] temp = edge_Of_firstLoop.get(seq_Of_edge.indexOf(vertexStack.point[current_edge_seq]));
vertex_explored_state.set(Integer.parseInt(temp[0])-1, "-1");
//当temp[0]不在point[ ]中时,将其添加到point
if(!vertexStack.pointContainsOrNot(temp[0])) {
vertexStack.addVertex(temp[0]);
}
//如果点A对应的边集为空,那么它一定是一个sink vertex。
if(temp.length == 1) {
System.out.println(temp[0] + " is a sink vertex!");
setSinkVertexs(temp[0]);
getReverseOfV(temp[0]);
vertexStack.addOrder(temp[0]);
vertex_state.remove(temp[0]);
vertexStack.popVertex();
current_edge_seq = vertexStack.stackEnd;
return;
}
//对指定的边集edge[startVertex]进行探索
for(int j=1; j<temp.length; j++) {
//遇到未探索的点时,将其作为startVertex
if(vertex_state.contains(temp[j]) && !vertex_explored_state.get(Integer.parseInt(temp[j])-1).equals("-1")) {
startVertex = temp[j];
//father_edge_seq = current_edge_seq;
//current_edge_seq = getCurrentEdgeSeq(startVertex);
current_edge_seq = seq_Of_edge.indexOf(startVertex);
//vertex_state.remove(temp[j]);
//vertexStack.addVertex(temp[j]);
return;
}
//edge[startVertex]读取到最后一个点时,这个点也被explore过,那么startVertex点就是个sink点
if(j == temp.length-1 && vertex_explored_state.get(Integer.parseInt(temp[j])-1).equals("-1")) {
System.out.println(temp[0] + " is a sink vertex!");
setSinkVertexs(temp[0]);
//System.out.println("SinkVertexs: " + sinkVertexs.get(sinkVertexs.size()-1));
getReverseOfV(temp[0]);
vertexStack.addOrder(temp[0]);
vertexStack.popVertex();
vertex_state.remove(temp[0]);
current_edge_seq = seq_Of_edge.indexOf(vertexStack.point[vertexStack.stackEnd]);
return;
}
}
}
public static int linkedOrNot(String vertex, String [] edge) {
int flags = 1;
if(edge.length == 1) {
return 1;
}
for(int i=1; i<edge.length; i++) {
if(edge[i].equals(vertex)) {
flags = -1;
break;
}
}
return flags;
}
public static void setSinkVertexs(String sinkvertex) {
//加入到DFS()中去,将每次的sinkvertex存入sinkVertexs
sinkVertexs.add(sinkvertex);
System.out.println("add " + sinkvertex + " in sinkVertexs!");
System.out.println("Now sinkVertexs.size is " + sinkVertexs.size());
}
public static void getReverseOfV(String startpoint) {
int size = edge_Of_firstLoop.size();
int seq = 0;
int length = 1;
String [] temp = new String[size];
temp[seq] = startpoint;
for(int i=0; i<size; i++) {
int lon = linkedOrNot(startpoint,edge_Of_firstLoop.get(i));
if(lon == -1) {
seq++;
temp[seq] = edge_Of_firstLoop.get(i)[0];
length++;
}
}
String [] temp1 = new String[length];
System.arraycopy(temp, 0, temp1, 0, length);
edge_Of_SecondLoop.add(temp1);
}
public static String getStartVertex() {
System.out.println("please input the source vertex:");
String s = new Scanner(System.in).nextLine();
return s;
}
public static int getCurrentEdgeSeq(String start) {
int flag = -1;
for(int i=0; i<edge_Of_firstLoop.size(); i++) {
if(edge_Of_firstLoop.get(i)[0].equals(start)) {
flag = i;
break;
}
}
return flag;
}
public static int getCurrentEdgeSeq_SecondLoop(String start) {
int flag = -1;
for(int i=edge_Of_SecondLoop.size()-1; i>=0; i--) {
if(edge_Of_SecondLoop.get(i)[0].equals(start)) {
flag = i;
break;
}
}
return flag;
}
}