Performing Breadth First Search recursively

后端 未结 21 2343
不思量自难忘°
不思量自难忘° 2020-11-28 01:12

Let\'s say you wanted to implement a breadth-first search of a binary tree recursively. How would you go about it?

Is it possible using only the call-stack

相关标签:
21条回答
  • 2020-11-28 01:39

    I would like to add my cents to the top answer in that if the language supports something like generator, bfs can be done co-recursively.

    To begin with, @Tanzelax's answer reads:

    Breadth-first traversal traditionally uses a queue, not a stack. The nature of a queue and a stack are pretty much opposite, so trying to use the call stack (which is a stack, hence the name) as the auxiliary storage (a queue) is pretty much doomed to failure

    Indeed, ordinary function call's stack won't behave like a normal stack. But generator function will suspend the execution of function so it gives us the chance to yield next level of nodes' children without delving into deeper descendants of the node.

    The following code is recursive bfs in Python.

    def bfs(root):
      yield root
      for n in bfs(root):
        for c in n.children:
          yield c
    

    The intuition here is:

    1. bfs first will return the root as first result
    2. suppose we already have the bfs sequence, the next level of elements in bfs is the immediate children of previous node in the sequence
    3. repeat the above two procedures
    0 讨论(0)
  • 2020-11-28 01:40

    I had to implement a heap traversal which outputs in a BFS order. It isn't actually BFS but accomplishes the same task.

    private void getNodeValue(Node node, int index, int[] array) {
        array[index] = node.value;
        index = (index*2)+1;
    
        Node left = node.leftNode;
        if (left!=null) getNodeValue(left,index,array);
        Node right = node.rightNode;
        if (right!=null) getNodeValue(right,index+1,array);
    }
    
    public int[] getHeap() {
        int[] nodes = new int[size];
        getNodeValue(root,0,nodes);
        return nodes;
    }
    
    0 讨论(0)
  • 2020-11-28 01:41

    The dumb way:

    template<typename T>
    struct Node { Node* left; Node* right; T value; };
    
    template<typename T, typename P>
    bool searchNodeDepth(Node<T>* node, Node<T>** result, int depth, P pred) {
        if (!node) return false;
        if (!depth) {
            if (pred(node->value)) {
                *result = node;
            }
            return true;
        }
        --depth;
        searchNodeDepth(node->left, result, depth, pred);
        if (!*result)
            searchNodeDepth(node->right, result, depth, pred);
        return true;
    }
    
    template<typename T, typename P>
    Node<T>* searchNode(Node<T>* node, P pred) {
        Node<T>* result = NULL;
        int depth = 0;
        while (searchNodeDepth(node, &result, depth, pred) && !result)
            ++depth;
        return result;
    }
    
    int main()
    {
        // a c   f
        //  b   e
        //    d
        Node<char*>
            a = { NULL, NULL, "A" },
            c = { NULL, NULL, "C" },
            b = { &a, &c, "B" },
            f = { NULL, NULL, "F" },
            e = { NULL, &f, "E" },
            d = { &b, &e, "D" };
    
        Node<char*>* found = searchNode(&d, [](char* value) -> bool {
            printf("%s\n", value);
            return !strcmp((char*)value, "F");
        });
    
        printf("found: %s\n", found->value);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-28 01:44

    I found a very beautiful recursive (even functional) Breadth-First traversal related algorithm. Not my idea, but i think it should be mentioned in this topic.

    Chris Okasaki explains his breadth-first numbering algorithm from ICFP 2000 at http://okasaki.blogspot.de/2008/07/breadth-first-numbering-algorithm-in.html very clearly with only 3 pictures.

    The Scala implementation of Debasish Ghosh, which i found at http://debasishg.blogspot.de/2008/09/breadth-first-numbering-okasakis.html, is:

    trait Tree[+T]
    case class Node[+T](data: T, left: Tree[T], right: Tree[T]) extends Tree[T]
    case object E extends Tree[Nothing]
    
    def bfsNumForest[T](i: Int, trees: Queue[Tree[T]]): Queue[Tree[Int]] = {
      if (trees.isEmpty) Queue.Empty
      else {
        trees.dequeue match {
          case (E, ts) =>
            bfsNumForest(i, ts).enqueue[Tree[Int]](E)
          case (Node(d, l, r), ts) =>
            val q = ts.enqueue(l, r)
            val qq = bfsNumForest(i+1, q)
            val (bb, qqq) = qq.dequeue
            val (aa, tss) = qqq.dequeue
            tss.enqueue[org.dg.collection.BFSNumber.Tree[Int]](Node(i, aa, bb))
        }
      }
    }
    
    def bfsNumTree[T](t: Tree[T]): Tree[Int] = {
      val q = Queue.Empty.enqueue[Tree[T]](t)
      val qq = bfsNumForest(1, q)
      qq.dequeue._1
    }
    
    0 讨论(0)
  • 2020-11-28 01:46

    The following seems pretty natural to me, using Haskell. Iterate recursively over levels of the tree (here I collect names into a big ordered string to show the path through the tree):

    data Node = Node {name :: String, children :: [Node]}
    aTree = Node "r" [Node "c1" [Node "gc1" [Node "ggc1" []], Node "gc2" []] , Node "c2" [Node "gc3" []], Node "c3" [] ]
    breadthFirstOrder x = levelRecurser [x]
        where levelRecurser level = if length level == 0
                                    then ""
                                    else concat [name node ++ " " | node <- level] ++ levelRecurser (concat [children node | node <- level])
    
    0 讨论(0)
  • 2020-11-28 01:48

    Let v be the starting vertex

    Let G be the graph in question

    The following is the pseudo code without using queue

    Initially label v as visited as you start from v
    BFS(G,v)
        for all adjacent vertices w of v in G:
            if vertex w is not visited:
                label w as visited
        for all adjacent vertices w of v in G:
            recursively call BFS(G,w)
    
    0 讨论(0)
提交回复
热议问题