簡體   English   中英

這種廣度優先搜索如何在Java中轉換為靜態方法?

[英]How would this Breadth-First-Search be converted into a static method in Java?

我用Python編寫了此靜態方法來進行廣度優先搜索。 但是,我主要使用Java,並且想要了解在給定泛型等情況下數據結構如何轉換為Java。我的代碼是:

def bfs(graph, start_vertex, target_value):
  path = [start_vertex] #a list that contains start_vertex
  vertex_and_path = [start_vertex, path] #a list that contains start_vertex and path
  bfs_queue = [vertex_and_path]
  visited = set() #visited defined as an empty set

  while bfs_queue: #while the queue is not empty
    current_vertex, path = bfs_queue.pop(0) #removes element from queue and sets both equal to that first element
    visited.add(current_vertex) #adds current vertex to visited list

    for neighbor in graph[current_vertex]: #looks at all neighboring vertices
      if neighbor not in visited: #if neighbor is not in visited list
        if neighbor is target_value: #if it's the target value
          return path + [neighbor] #returns path with neighbor appended
        else:
          bfs_queue.append([neighbor, path + [neighbor]]) #recursive call with path that has neighbor appended

我將在其上使用的圖形將是:

myGraph = { //I'm not sure how to structure this in Java
    'lava': set(['sharks', 'piranhas']),
    'sharks': set(['lava', 'bees', 'lasers']),
    'piranhas': set(['lava', 'crocodiles']),
    'bees': set(['sharks']),
    'lasers': set(['sharks', 'crocodiles']),
    'crocodiles': set(['piranhas', 'lasers'])
  }

我會這樣稱呼

public static void main(String[] args){
    System.out.println(bfs(myGraph, "crocodiles", "bees"));
}

到目前為止,這是我擁有的Java:

    public class BreadthFirstSearch{

    ///NOT DONE YET
    public static ArrayList<String> BFS(Map<String, String[]> graph, String start, String target) {
            List<String> path = new ArrayList<>();
            path.add(start);
            List<String> vertexAndPath = new ArrayList<>();
            vertexAndPath.add(start);
            vertexAndPath.add(path.get(0));
            ArrayList<String> queue = new ArrayList<>();
            queue.add(vertexAndPath.get(0));
            queue.add(vertexAndPath.get(1));
            Set<String> visited = new HashSet<String>();
            while(!queue.isEmpty()) {
                String currentVertex = queue.remove(0);
                String curVerValue = currentVertex;
                path.add(currentVertex);
                .
                .
                .
            }
        }
}

努力翻譯。 讓我提供我的代碼,然后提供一個解釋:

import java.util.*;

class BreadthFirstSearch {
    public static ArrayList<String> BFS(
        Map<String, String[]> graph, String start, String target
    ) {
        Map<String, String> visited = new HashMap<>();
        visited.put(start, null);
        ArrayDeque<String> deque = new ArrayDeque<>();
        deque.offer(start);

        while (!deque.isEmpty()) {
            String curr = deque.poll();

            if (curr.equals(target)) {
                ArrayList<String> path = new ArrayList<>();
                path.add(curr);

                while (visited.get(curr) != null) {
                    curr = visited.get(curr);
                    path.add(curr);
                }

                Collections.reverse(path);
                return path;
            }

            for (String neighbor : graph.get(curr)) {
                if (!visited.containsKey(neighbor)) {
                    visited.put(neighbor, curr);
                    deque.offer(neighbor);
                }
            }
        }

        return null;
    }

    public static void main(String[] args) {
        Map<String, String[]> myGraph = new HashMap<>();
        myGraph.put(
            "lava", new String[] {"sharks", "piranhas"}
        );
        myGraph.put(
            "sharks", new String[] {"lava", "bees", "lasers"}
        );
        myGraph.put(
            "piranhas", new String[] {"lava", "crocodiles"}
        );
        myGraph.put(
            "bees", new String[] {"sharks"}
        );
        myGraph.put(
            "lasers", new String[] {"sharks", "crocodiles"}
        );
        myGraph.put(
            "crocodiles", new String[] {"piranhas", "lasers"}
        );
        System.out.println(BFS(myGraph, "crocodiles", "bees"));
        System.out.println(BFS(myGraph, "crocodiles", "crocodiles"));
        System.out.println(BFS(myGraph, "crocodiles", "zebras"));
    }
}

產量

[crocodiles, lasers, sharks, bees]
[crocodiles]
null

說明

我做出了設計決定,避免在圖表中的每個節點上復制path ArrayList,而采用visited哈希表(將節點存儲在childNode => parentNode對中)。 這樣,一旦定位了目標節點,我便一步一步地回溯了創建路徑的過程,而不是為每個節點都建立了路徑,而大多數路徑最終都無濟於事。 這在時空上更有效; 使用[] + [] O(n)列表串聯運算符,Python太容易破壞時間復雜度。

使用child => parent visited HashMap也更易於用Java編寫代碼,因為Java沒有輕量級的Pair / Tuple / struct可以方便地將不同類型存儲為隊列中的節點。 若要執行將2元素列表傳遞到隊列中的Python操作,您要么必須編寫自己的Pair類,使用兩個ArrayDeques,要么避免使用泛型並使用強制轉換,所有這些都很難看(特別是最后,這也是不安全的)。

我在您的代碼中注意到的另一個問題是將ArrayList用作隊列。 列表前面的插入和刪除操作是O(n)操作,因為列表中的所有元素都必須在基礎數組中向前或向后移動以保持順序。 Java中的最佳隊列結構是ArrayDeque ,與Queue集合不同,它在兩端都提供O(1)添加和刪除,並且不是線程安全的。

同樣,在Python中,使用deque集合會發現性能最佳,該集合為所有排隊需求提供了快速的popleft操作。 此外,在Python實現中,哈希中的每個鍵都指向set ,這是可以的,但是當列表可以執行時,這似乎是不必要的結構(您已切換到Java中的原始數組)。 如果您不操縱圖而僅遍歷鄰居,這似乎是理想的。

請注意,此代碼還假定每個節點都像輸入一樣,在代表圖形的哈希中都有一個鍵。 如果計划在節點的哈希值中可能沒有鍵的位置輸入圖,則需要確保graph.get(curr) containsKeycontainsKey檢查,以避免崩潰。

另一個值得一提的假設:請確保您的圖形不包含null因為所visited哈希依賴於null來表示子代沒有父代並且是搜索的開始。

您將需要創建一個單獨的類來保存圖的節點。 這些節點不能都是靜態的,因為它們都有唯一的頂點。 從那里開始,其余部分非常相似。

public class Node {
    public String name;
    public ArrayList<Node> vertices;
    public void addEdge(Node node) {
        edges.add(node);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM