Java的ArraList.forEach在while循环中无法正常工作

时间:2019-06-08 03:31:20

标签: java arraylist foreach

我正在使用Java实现对无向图的广度优先搜索。但是,仅处理一个顶点。即使正确添加了其他顶点的邻接节点,也将返回0。

public class Graph {
   class Vertex {
        String label;
        ArrayList<Vertex> adjNodeList;
        boolean isVisited;

        public Vertex(String label) {
            this.label = label;
            this.adjNodeList = new ArrayList<>();
            this.isVisited = false;
        }
   }

   ArrayList<Vertex> vertices;

   public Graph() {
        this.vertices = new ArrayList<>();    
   }

   public void addNode(String label) {
       this.vertices.add(new Vertex(label));
   }

   public void addEdge(String start, String end) {
       this.vertices.forEach((e) -> {
           if(e.label.equalsIgnoreCase(start)) {
               e.adjNodeList.add(new Vertex(end));
           }
       });
   }

   public void printGraph() {
      this.vertices.forEach((e -> {
          System.out.print("Vertex - " + e.label + " -> ");
          e.adjNodeList.forEach((v -> {
              System.out.print(v.label);
          }));

          System.out.println();
      }));
   }

   public void breadthFirstSearch() {
        Queue<Vertex> theQueue = new LinkedList<>();

        Vertex rv = this.vertices.get(0);
        rv.isVisited = true;
        theQueue.add(rv);

        while(!theQueue.isEmpty()) {
            Vertex vertex = theQueue.remove();
            System.out.println("Processing - " + vertex.label);
            System.out.println("List size - " + vertex.adjNodeList.size());

            vertex.adjNodeList.forEach((e) -> {
                if(!e.isVisited) {
                    e.isVisited = true;
                    theQueue.add(e);
                    System.out.println("Enqueued - " + e.label);
                }
            });
        }
   }

打印图形时,它可以正确显示所有边缘,但是BFS方法只能处理A及其边缘,如下所示...

Vertex - A -> BC
Vertex - B -> G
Vertex - C -> D
Vertex - D -> E
Vertex - E -> 
Vertex - G -> 
Processing - A
List size - 2
Enqueued - B
Enqueued - C
Processing - B
List size - 0
Processing - C
List size - 0

1 个答案:

答案 0 :(得分:1)

  

即使已正确添加它们。

我以此为前提,当您调用addEdge时(例如,通过addEdge("A", "B");进行调用),我们可以假定您已经调用了addNode("A")addNode("B")

如果是这样,那么问题出在您的addEdge方法中:

public void addEdge(String start, String end) {
   this.vertices.forEach((e) -> {
       if(e.label.equalsIgnoreCase(start)) {
           e.adjNodeList.add(new Vertex(end));
       }
   });

}

因此,给定addEdge("A", "B");,此代码将查找您已添加的起始顶点“ A”-但随后将创建一个new Vertex“ B”,而不查找可能已添加的任何顶点。该新顶点具有一个空的adjNodeList,它将保持为空。

换句话说,从“ A”引用的顶点“ B”与this.vertices中的顶点“ B”是不同的实例。

因此,您应该更改addEdge(并且还要进行addNode的确定工作),以便首先在this.vertices中查找现有顶点。

例如这样的东西:

 public Vertex fetchNode(String label) {
   return this.vertices.stream()
              .filter(v -> v.getLabel().equals(label))
              .findAny()
              .orElseGet( () -> {
                  Vertex newVertex = new Vertex(label));
                  this.vertices.add(newVertex);
                  return newVertex;
               });
  }

  public void addEdge(String start, String end) {
     this.vertices.forEach((e) -> {
         if(e.label.equalsIgnoreCase(start)) {
             e.adjNodeList.add(fetchNode(end));
         }
     });
  }