簡體   English   中英

Java 中的 BFS(廣度優先搜索)算法 -> 無法通過不獲取節點的兄弟節點來實現 bfs

[英]BFS (Breadth First Search) Algorithm in Java -> Cannot implement bfs by not getting node's siblings

我有一個關於從主節點獲取所有兄弟節點並實現Java編寫的進程n廣度優先搜索算法的問題。

我該如何實施?

我分享了如下所示的代碼片段。

這是我的節點 class,如下所示。

public class Node{
    Node(int data){
       this.data = data;
       this.left = null;
       this.right = null;
       this.visited = false;
    }
    int data;
    Node left;
    Node right;
    boolean visited;

    // getter and setter 
}

這是下面顯示的初始化過程。

Node node1 = new Node(1);
Node node7 = new Node(7);
Node node9 = new Node(9);
Node node8 = new Node(8);
Node node2 = new Node(2);
Node node3 = new Node(3);
node1.left = node7;
node1.right = node9;
node7.right = node8;
node9.right = node3;
node9.left = node2;

這是下面顯示的方法。

public static void bfs(Node root){
        if (root == null){
            return;
        }
        
        Node temp; //a binary tree with a inner generic node class
        Queue<Node> queue = new LinkedList<>(); //can't instantiate a Queue since abstract, so use LLQueue
        
        queue.add(root);
        root.visited = true;
        while (!queue.isEmpty())
        {
            temp = queue.poll(); //remove the node from the queue
            
            // How can I get all siblings of the node like
            // for (Node sibling : temp.getSiblingNodes())
            // sibling.visited=true;
            // queue.add(sibling);
            
        }

        // get the result as a list
    }

您不應該嘗試獲取節點的兄弟節點。 如果將當前節點的節點推送到隊列中,您將保證按兄弟順序將它們拉出隊列。 這里重要的是當一個節點從隊列中被拉出時你訪問它,而不是當它被添加到隊列中時。

所以你的 function 可以變成這樣:

    public static List<Node> bfs(Node root){
        Queue<Node> queue = new LinkedList<>();
        List<Node> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        queue.add(root); // Don't visit this root node yet...
        while (!queue.isEmpty())
        {
            Node node = queue.poll();
            result.add(node); // Here we visit the node
            // Add the children of the visited node to the queue
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);
        }
        return result;
    }

調用者可以這樣做:

    for (Node node : bfs(node1)) {
        System.out.println(node.data);
    }

由於Node有一個屬性isVisited ,我假設圖中可能存在循環。

該算法可以描述為以下步驟:

  • root標記為已訪問並將其放入隊列。

  • 然后直到Queue不為空,重復:

    • 從Queue的頭部移除Node( current Node);
    • 檢查其left right節點。 如果一個子節點存在(即不是null )並且還沒有被訪問過,那么將這個節點添加到隊列和兄弟節點的結果列表中,並將子節點的isVisited屬性設置為true

這就是它可能的實現方式:

public static List<Node> bfs(Node root) {
    if (root == null) return Collections.emptyList();
    
    List<Node> siblings = new ArrayList<>();
    Queue<Node> queue = new ArrayDeque<>(); // performs better than LinkedList
    
    queue.add(root);
    // siblings.add(root); // uncomment this line ONLY if you need the root-Node to be present in the result
    root.visited = true;
    
    while (!queue.isEmpty()) {
        Node current = queue.poll();

        tryAdd(siblings, queue, current.left);
        tryAdd(siblings, queue, current.right);
    }
    return siblings;
}

public static void tryAdd(List<Node> siblings, Queue<Node> queue, Node next) {
    if (next != null && !next.isVisited()) {
        queue.add(next);
        siblings.add(next);
        next.setVisited(true);
    }
}

為了避免right left節點重復相同的操作,我創建了方法tryAdd()

我們可以通過引入Predicate來改變其條件邏輯(在這種情況下,條件很短且可讀性強,並且顯示此選項是為了教育目的):

public static final Predicate<Node> IS_NULL_OR_VISITED =
    Predicate.<Node>isEqual(null).or(Node::isVisited);

public static void tryAdd(List<Node> siblings, Queue<Node> queue, Node next) {
    if (IS_NULL_OR_VISITED.test(next)) return;
    
    queue.add(next);
    siblings.add(next);
    next.setVisited(true);
}

暫無
暫無

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

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