JAVA - BFS到图表中有限的友谊等级

时间:2016-11-13 20:41:52

标签: java algorithm graph breadth-first-search

我正在为简单的社交网络开发无向图实现。用户使用他们的ID(整数)来表示,我需要找到不同级别的友谊 我使用了Adjacency List方法,因为我的图表非常稀疏。我使用了一个hashmap来保存用户和他们的朋友:

Map<Integer, Set<Integer>> graph;  

使用此实现,我能够找到第一和第二级友谊。但是,我写了一个方法,使用BFS来查找两个用户是否是第四级朋友。

例如,如果图表包含以下边缘:
1-2
2-3
3-4
4-5
然后1和5是第四级朋友,当1和5作为参数传递给它时,我的方法应该返回true。

问题是我的方法在main中调用时总是返回false,即使方法本身已经过测试且是正确的!这是方法,并且它是正确和有效的。

public boolean checkLevelBFS(Integer source, Integer dest) {
    Queue<Integer> toVisitQueue = new LinkedList<>(graph.get(source));
    Set<Integer> visited = new HashSet<>();
    visited.add(source);
    Integer inreaser = new Integer(-1); // indicator for level increase
    toVisitQueue.add(inreaser);
    int level = 1; // because we already passed the source and started from its children nodes
    while (level <= 4 && !toVisitQueue.isEmpty()) {
        Integer currentNode = toVisitQueue.remove();
        if (currentNode.equals(dest)) {
            return true;
        }
        if (visited.contains(currentNode)) {
            continue;
        }
        if (currentNode.equals(inreaser)) {
            level++;
            toVisitQueue.add(inreaser);
            continue;
        }
        visited.add(currentNode);
        for (Integer child : graph.get(currentNode)) {
            if (!visited.contains(child)){
                toVisitQueue.add(child);
            }
        }
    }
    return false;
}

使代码返回false的部分如下:

public static void main(String[] args) {
    Basics x = new Basics();
    x.graph = new HashMap<>();

    Set<Integer> s = new HashSet<>();

    s.add(2);
    x.graph.put(1, s);

    s = new HashSet<>();
    s.add(1);
    s.add(3);
    x.graph.put(2, s);

    s = new HashSet<>();
    s.add(2);
    s.add(4);
    x.graph.put(3, s);

    s = new HashSet<>();
    s.add(3);
    s.add(5);
    x.graph.put(4, s);

    s = new HashSet<>();
    s.add(4);
    s.add(6);
    x.graph.put(5, s);

    s = new HashSet<>();
    s.add(5);
    x.graph.put(6, s);

    if (!x.initialCheck(1, 5)) {
        System.out.println("A new user is involved");
    } else {
        if (x.levelOneFriends(1, 5)) {
            System.out.println("friends");
        } else {
            System.out.println("not friends");
            if (x.levelTwoFriends(1, 5)) {
                System.out.println("friends level 2");
            } else {
                System.out.println("not friends of level 2");
                if (x.checkLevelBFS(1, 5)) {
                    System.out.println("YES - friends of level 4");
                } else {
                    System.out.println("NO - not friends of level 4");
                }
            }
        }
    }
    System.out.println(x.checkLevelBFS(1, 2));
    System.out.println(x.checkLevelBFS(1, 3));
    System.out.println(x.checkLevelBFS(1, 4));
    System.out.println(x.checkLevelBFS(1, 5));
    System.out.println(x.checkLevelBFS(1, 6));
}

输出:

not friends
not friends of level 2
NO - not friends of level 4
false
false
false
false
false

前两行是正确的输出,第三行是不正确的1和5是4级的油炸,应该打印是 -
以下&#39; false&#39;输出也很怪异!

&#39; initialCheck&#39;检查图中是否有两个用户中的任何一个 &#39; levelOneFriends&#39;检查这两个对象是否是直接的朋友 &#39; levelTwoFriends&#39;检查这两个对象是否属于朋友的朋友关系。

任何帮助?

谢谢!

1 个答案:

答案 0 :(得分:0)

[OP的评论显示levelTwoFriends]

后编辑
public boolean levelTwoFriends(Integer user1, Integer user2) { 
  Collection<Integer> c = graph.get(user1);
  // c.retainAll(graph.get(user2)); 
  // return !c.isEmpty(); 

  // true only if a non-void intersection
  return false==Collections.disjoint(c, graph.get(user2));
}

或作为单行

public boolean levelTwoFriends(Integer user1, Integer user2) { 
  return false==Collections.disjoint( graph.get(user1), graph.get(user2) );
}

[使用x.initialCheck更新后编辑]

然后,您的错误必须在x.initialCheck以及您在实际进入x.checkLevelBFS之前所做的其他事情中。验证x.initialCheckx.levelOneFriends是否违反了邻接列表的内部表示中的修改(必须在那里 - 在调试器中运行并密切关注内容的修改)。我为什么这么说?因为以下代码按预期工作:

  static public void main(String[] args) {
    ExampleTest x=new ExampleTest(); // in your case, it's Basics

    x.graph=new HashMap<>();
    x.graph.put(1, new HashSet<>(Arrays.asList(2)));
    x.graph.put(2, new HashSet<>(Arrays.asList(1,3)));
    x.graph.put(3, new HashSet<>(Arrays.asList(2,4)));
    x.graph.put(4, new HashSet<>(Arrays.asList(3,5)));
    x.graph.put(5, new HashSet<>(Arrays.asList(4,6)));
    x.graph.put(6, new HashSet<>(Arrays.asList(5)));
    System.out.println(x.checkLevelBFS(1, 2)); // true
    System.out.println(x.checkLevelBFS(1, 3)); // true
    System.out.println(x.checkLevelBFS(1, 4)); // true
    System.out.println(x.checkLevelBFS(1, 5)); // true
    System.out.println(x.checkLevelBFS(1, 6)); // false
  }
  

“问题是我的方法总是返回false!”

但事实并非如此!你的错误可能在其他地方!!!

我会将此标记为为我工作并关闭错误。

我的代码用于推动测试。

class ExampleTest {
  Map<Integer, Set<Integer>> graph;  

  static public void main(String[] args) {
    ExampleTest x=new ExampleTest();
    x.graph=new HashMap<>();
    x.graph.put(1, new HashSet<>(Arrays.asList(2)));
    x.graph.put(2, new HashSet<>(Arrays.asList(3)));
    x.graph.put(3, new HashSet<>(Arrays.asList(4)));
    x.graph.put(4, new HashSet<>(Arrays.asList(5)));
    x.graph.put(5, new HashSet<>(Arrays.asList(6)));
    System.out.println(x.checkLevelBFS(1, 2)); // true
    System.out.println(x.checkLevelBFS(1, 3)); // true
    System.out.println(x.checkLevelBFS(1, 4)); // true
    System.out.println(x.checkLevelBFS(1, 5)); // true
    System.out.println(x.checkLevelBFS(1, 6)); // false
  }

  // verbatim copy of your method here
  public boolean checkLevelBFS(Integer source, Integer dest) {
    Queue<Integer> toVisitQueue = new LinkedList<>(graph.get(source));
    Set<Integer> visited = new HashSet<>();
    visited.add(source);
    Integer inreaser = new Integer(-1); // indicator for level increase
    toVisitQueue.add(inreaser);
    int level = 1; // because we already passed the source and started from its children nodes
    while (level <= 4 && !toVisitQueue.isEmpty()) {
      Integer currentNode = toVisitQueue.remove();
      if (currentNode.equals(dest)) {
        return true;
      }
      if (visited.contains(currentNode)) {
        continue;
      }
      if (currentNode.equals(inreaser)) {
        level++;
        toVisitQueue.add(inreaser);
        continue;
      }
      visited.add(currentNode);
      for (Integer child : graph.get(currentNode)) {
        if (!visited.contains(child)){
          toVisitQueue.add(child);
        }
      }
    }
    return false;
  }

}