问题
I have a Node class as follows:
public class Node{
Object data;
List<Node> children;
}
I need to traverse this tree in post order and I am using Guava TreeTraverser for for the same.
TreeTraverser<Node> treeTraverser = new TreeTraverser<Node>() {
@Override
public Iterable<Node> children(Node node) {
return node.children;
}
};
treeTraverser.postOrderTraversal(node);
The catch is that there chances that the given tree could have circular dependencies(means it could be a cyclic graph). What would be an efficient way to detect circular dependencies?
回答1:
By definition, a tree is an acyclic connected graph. Therefore, there is no such thing as a tree with circular dependencies.
You can find cycles in a graph by applying depth-first traversal, and looking for nodes that have been visited the way down. If you visit a node that you have seen during prior steps of DFS, the graph is not a tree.
See this Q&A for advanced cycle detection algorithms.
回答2:
In simple words Tree is a non cyclic data structure
and when there are cycles then it becomes a Graph
.
Above is an example of a graph. You can represent it using Adjacency list or adjacency matrix. You can refer to http://krishnalearnings.blogspot.in/2015/11/basics-of-graph-in-computer-science.html for basics of Graphs.
In the picture above we can represent it as below (In your question, you have used an adjacency list kind of representation).
int[][] graph = { {0,1,0,0,0,0},
{0,0,1,0,0,0},
{0,0,0,1,1,0},
{0,0,0,0,0,0},
{0,0,0,0,0,1},
{0,1,0,0,0,0},
};
1 represents an edge from corresponding row numbered vertex to column numbered vertex.
We can write a simple method to detect the presence of cycle and also print any one cycle in the graph.
static int[] cycleElements;
static int cycleElementIndex = 0;
static boolean cycleFound = false;
static final int NEW = 0;
static final int PUSHED = 1;
static final int POPPED = 2;
public static int findCycle(int[][] graph,int N, int u, int[] states){
for(int v = 0; v < N; v++){
if(graph[u][v] == 1){
if(states[v] == PUSHED){
// cycle found
cycleFound = true;
return v;
}else if(states[v] == NEW){
states[v] = PUSHED;
int poppedVertex = findCycle(graph, N, v, states);
states[v] = POPPED;
if(cycleFound){
if(poppedVertex == u){
cycleElements[cycleElementIndex++] = v;
cycleElements[cycleElementIndex++] = u;
cycleFound = false;
}else{
cycleElements[cycleElementIndex++] = v;
return poppedVertex;
}
}
}
}
}
return -1;
}
public static void main(String[] args) {
int N = 6;
int[][] graph = { {0,1,0,0,0,0},
{0,0,1,0,0,0},
{0,0,0,1,1,0},
{0,0,0,0,0,0},
{0,0,0,0,0,1},
{0,1,0,0,0,0},
};
cycleElements = new int[N];
int[] states = new int[N];
states[0] = PUSHED;
findCycle(graph,N,0,states);
for(int i = 0; i < cycleElementIndex; i++){
System.out.println(cycleElements[i]);
}
}
You can easily transform above approach to adjacency list if you wish, though representation does not matter much ( only adjacency list may save your space as compared to adjacency matrix)
来源:https://stackoverflow.com/questions/37907339/how-to-detect-circular-reference-in-a-tree