作为该顶点的一种方法,遍历图的顶点

时间:2018-09-30 03:31:52

标签: java algorithm

我有一个目前无法解决的问题。

假设我有一个类Member,其中包含与给定成员相关的成员列表的信息: ArrayList<Member> links;

此外,此类的方法称为canBeLinked(Member member)

显然返回布尔值,该布尔值定义特定成员是否可以直接或间接与给定成员链接。

说“直接”是指共同关系A-> B;如果例如A-> B,B-> C,那么它也应该返回true。 还请记住,如果A-> B,则B->A。 这样我们得到了无向图的模型。

我的困惑是如何实现此功能;我猜它一定是递归的,但要点是它不是两个参数的函数(例如,如果它是静态函数,我们可以很容易地编写函数canBeLinked(Member a, Member b),那么互联网上有很多此类图的实现)。

我的第一种方法是写这样的东西:

public boolean canBeLinked(Member member) {
   if (this.links.contains(member)) {
       return true;
   }
   else {
       for (Member m : links)
           if (m.canBeLinked(member)) return true;
   }
   return false;
}

我肯定会得到一个StackOverflowException;  假设我们有这样的关系:

A -> B
B -> D
B -> E
D -> C
E -> C

致电

a.canBeLinked(c) 

我们得到:   1)首先,我们检查“ a”的成员列表中是否已经包含“ c”;   2)这是不正确的,所以请进入for循环;   3)由于列表中只有一个成员(“ b”),因此我们调用b.canBeLinked(c);   4)“ c”也不是“ b”列表的成员,因此它也进入“ for”语句   5)现在我们很麻烦,因为“ b”的列表不仅包含“ e”和“ d”,而且还包含“ a”,这导致我们进入第1页;它会永远持续下去(直到内存用完)

能否请您解释如何解决此问题?我敢肯定,这很简单,但我对此一无所知,而且肯定错过了它的一些要点。

1 个答案:

答案 0 :(得分:1)

幸运的是,修复非常简单;您需要跟踪搜索中已经访问过哪个Members,例如使用Set<Member>,并且不要循环访问已见过的任何Members。在查询链接的Members之前,请将当前的Member添加到已访问的集合中。

由于您的递归函数现在需要传递一组访问成员,因此最好将其拆分为从公用方法调用的privateprotected方法。

public boolean canBeLinked(Member member) 
{
  return canBeLinked(member, new HashSet<>());
}

private boolean canBeLinked(Member member, Set<Member> visited)
{
  if (this.links.contains(member)) {
      return true;
  }
  else {
    visited.add(this);
    for (Member m : links)
    {
      if (!visited.contains(m)) return m.canBeLinked(member, visited);
    }
  }
  return false;
}