如何检测树中的循环引用?

时间:2016-06-19 12:41:57

标签: java data-structures tree guava tree-traversal

我有一个Node类,如下所示:

public class Node{
    Object data;
    List<Node> children;
}

我需要按照邮政顺序遍历这棵树,而我正在使用Guava TreeTraverser

    TreeTraverser<Node> treeTraverser = new TreeTraverser<Node>() {
                @Override
                public Iterable<Node> children(Node node) {
                    return node.children;
                }
            };

treeTraverser.postOrderTraversal(node);

问题是,给定的树可能具有循环依赖性(意味着它可能是循环图)。什么是检测循环依赖的有效方法?

2 个答案:

答案 0 :(得分:8)

根据定义,树是acyclic连接图。因此,没有具有循环依赖性的树。

您可以通过应用深度优先遍历并查找已经访问过的节点来查找图形中的循环。如果您访问在DFS之前的步骤中看到的节点,则图表树。

有关高级循环检测算法,请参阅此Q&A

答案 1 :(得分:0)

简单地说Tree is a non cyclic data structure,当有周期时,它就会成为Graph

enter image description here

以上是图表的示例。您可以使用邻接列表或邻接矩阵来表示它。您可以参考http://krishnalearnings.blogspot.in/2015/11/basics-of-graph-in-computer-science.html了解图表的基础知识。

在上图中我们可以表示如下(在您的问题中,您使用了邻接列表的表示形式)。

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表示从相应行编号的顶点到列编号顶点的边。

我们可以编写一种简单的方法来检测周期的存在,并在图表中打印任何一个周期。

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]);
    }
}

如果您愿意,您可以轻松地将上述方法转换为邻接列表,尽管表示无关紧要(与邻接矩阵相比,只有邻接列表可以节省您的空间)