209

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 as auxiliary storage?

dsolimano
  • 8,870
  • 3
  • 48
  • 63
Nate
  • 6,779
  • 8
  • 28
  • 21

24 Answers24

171

(I'm assuming that this is just some kind of thought exercise, or even a trick homework/interview question, but I suppose I could imagine some bizarre scenario where you're not allowed any heap space for some reason [some really bad custom memory manager? some bizarre runtime/OS issues?] while you still have access to the stack...)

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, unless you're doing something stupidly ridiculous with the call stack that you shouldn't be.

On the same token, the nature of any non-tail recursion you try to implement is essentially adding a stack to the algorithm. This makes it no longer breadth first search on a binary tree, and thus the run-time and whatnot for traditional BFS no longer completely apply. Of course, you can always trivially turn any loop into a recursive call, but that's not any sort of meaningful recursion.

However, there are ways, as demonstrated by others, to implement something that follows the semantics of BFS at some cost. If the cost of comparison is expensive but node traversal is cheap, then as @Simon Buchan did, you can simply run an iterative depth-first search, only processing the leaves. This would mean no growing queue stored in the heap, just a local depth variable, and stacks being built up over and over on the call stack as the tree is traversed over and over again. And as @Patrick noted, a binary tree backed by an array is typically stored in breadth-first traversal order anyway, so a breadth-first search on that would be trivial, also without needing an auxiliary queue.

Community
  • 1
  • 1
Tanzelax
  • 5,406
  • 2
  • 25
  • 28
  • 13
    This is indeed just a thought exercise. I can't really imagine a situation in which you'd actually want to do this. Thanks for the well thought out answer! – Nate Mar 31 '10 at 03:08
  • 5
    "*but I suppose I could imagine some bizarre scenario where you're not allowed any heap space for some reason*": dunno, I can imagine an embedded environment where only the stack (along with any read-only memory space) is available (it's actually quite easy and efficient to write software without using the heap at all if you know exactly what your program is going to do, which is usually the case in embedded software). So it's not that "bizarre" to me. Unusual, maybe, but not bizarre. – Thomas Aug 09 '13 at 05:40
  • 1
    I think that your answer may contain a reference to this article (https://www.ibm.com/developerworks/aix/library/au-aix-stack-tree-traversal/). It shows an implementation about what you wrote in the second part of your answer – incud Nov 10 '16 at 16:55
  • 1
    If the only constraint is to use "stacks" and "no queue" - Use two stacks to mimic a queue – Chaitanya Aug 16 '21 at 05:33
29

If you use an array to back the binary tree, you can determine the next node algebraically. if i is a node, then its children can be found at 2i + 1 (for the left node) and 2i + 2 (for the right node). A node's next neighbor is given by i + 1, unless i is a power of 2

Here's pseudocode for a very naive implementation of breadth first search on an array backed binary search tree. This assumes a fixed size array and therefore a fixed depth tree. It will look at parentless nodes, and could create an unmanageably large stack.

bintree-bfs(bintree, elt, i)
    if (i == LENGTH)
        return false

    else if (bintree[i] == elt)
        return true

    else 
        return bintree-bfs(bintree, elt, i+1)        
Alex
  • 7,639
  • 3
  • 45
  • 58
  • 1
    Nice. I overlooked the fact that we are dealing with a binary tree. The indexes can be assigned using a DFS. BTW, you forgot a return false at the first case. – sisis Mar 31 '10 at 01:33
  • I think I prefer the queueing method ;P. Added return false. – Patrick McMurchie Mar 31 '10 at 01:36
  • 1
    Clever. The idea of storing the nodes in an array and referencing them algebraically hadn't occurred to me. – Nate Mar 31 '10 at 03:03
25

I couldn't find a way to do it completely recursive (without any auxiliary data-structure). But if the queue Q is passed by reference, then you can have the following silly tail recursive function:

BFS(Q)
{
  if (|Q| > 0)
     v <- Dequeue(Q)
     Traverse(v)
     foreach w in children(v)
        Enqueue(Q, w)    

     BFS(Q)
}
sisis
  • 936
  • 7
  • 12
  • 8
    This is unnatural way, to add recursive to clean and correct function. – Mysterion Aug 09 '13 at 05:34
  • 1
    Completely disagree - I find it more natural - and also more useful; you can extend this method to pass down working state as you go through layers – tbjgolden Apr 11 '20 at 19:38
19

The following method used a DFS algorithm to get all nodes in a particular depth - which is same as doing BFS for that level. If you find out depth of the tree and do this for all levels, the results will be same as a BFS.

public void PrintLevelNodes(Tree root, int level) {
    if (root != null) {
        if (level == 0) {
            Console.Write(root.Data);
            return;
        }
        PrintLevelNodes(root.Left, level - 1);
        PrintLevelNodes(root.Right, level - 1);
    }
}

for (int i = 0; i < depth; i++) {
    PrintLevelNodes(root, i);
}

Finding depth of a tree is a piece of cake:

public int MaxDepth(Tree root) {
    if (root == null) {
        return 0;
    } else {
        return Math.Max(MaxDepth(root.Left), MaxDepth(root.Right)) + 1;
    }
}
Chris Nolet
  • 8,714
  • 7
  • 67
  • 92
Sanj
  • 261
  • 2
  • 6
  • Please pay a little bit more attention to your code formating. I did some changes. – Micha Aug 09 '13 at 05:24
  • But, hold on... is this a DFS rather than BFS? Because PrintLevelNodes does not return until `level` is zero. – Herrington Darkholme Feb 16 '14 at 11:30
  • 1
    @HerringtonDarkholme, Correct. It does DFS search but the outputs values as if it did a BFS for a level. Thanks for pointing out that. – Sanj May 09 '14 at 20:51
  • 2
    @Sanjay , this indeed is a good demonstration of how one might perform some action on nodes in DFS-order. It is not necessarily how one would actually "touch" nodes in DFS-order, but will certainly allow to recursively "act" on nodes in DFS order, in this case printing their values. – bunkerdive Aug 05 '14 at 23:55
8

A simple BFS and DFS recursion in Java:
Just push/offer the root node of the tree in the stack/queue and call these functions.

public static void breadthFirstSearch(Queue queue) {

    if (queue.isEmpty())
        return;

    Node node = (Node) queue.poll();

    System.out.println(node + " ");

    if (node.right != null)
        queue.offer(node.right);

    if (node.left != null)
        queue.offer(node.left);

    breadthFirstSearch(queue);
}

public static void depthFirstSearch(Stack stack) {

    if (stack.isEmpty())
        return;

    Node node = (Node) stack.pop();

    System.out.println(node + " ");

    if (node.right != null)
        stack.push(node.right);

    if (node.left != null)
        stack.push(node.left);

    depthFirstSearch(stack);
}
Pang
  • 9,564
  • 146
  • 81
  • 122
ThePatelGuy
  • 1,844
  • 1
  • 19
  • 18
  • 5
    It's a bit weird to pass stack as a parameter for DFS, because you already have implicit stack there. Also the question was to use only call stack as a data structure. – vladich Jan 23 '17 at 20:18
7

Here is a BFS recursive traversal Python implementation, working for a graph with no cycle.

def bfs_recursive(level):
    '''
     @params level: List<Node> containing the node for a specific level.
    '''
    next_level = []
    for node in level:
        print(node.value)
        for child_node in node.adjency_list:
            next_level.append(child_node)
    if len(next_level) != 0:
        bfs_recursive(next_level)


class Node:
    def __init__(self, value):
        self.value = value
        self.adjency_list = []
Jbeat
  • 151
  • 2
  • 12
5

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
Herrington Darkholme
  • 5,979
  • 1
  • 27
  • 43
  • I don't know Python but I think your code translates to [this C# code](https://dotnetfiddle.net/TEPkzC). It does the BFS traversal but crashes with a stackoverflow exception. I haven't figured out the why so far. However, I modified the algorithm so that it stops (and performs better probably). You find my working sample [here](https://dotnetfiddle.net/goS3an). – Adam Simon May 09 '20 at 19:23
  • This looks deceptively simple, but is really nifty actually (save for the suboptimal complexity). First recurses down, then does a preorder back, always starting from root. Recursion depth corresponds to tree height, so stops at correct level. This is repeated incrementally. – LogicBreaker Jul 26 '22 at 23:00
  • 1
    This implementation contains infinite recursion. It should fail with "stack overflow" error. Lol !! – IStranger Mar 18 '23 at 17:19
4

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
}
snv
  • 133
  • 1
  • 11
  • +1 for the beautiful algorithm. However, I found it still using a queue. The left side of "Rule 3" itself is actually the dequeue and enqueue operations. – Luke Lee Oct 27 '16 at 06:41
3

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;
}
Simon Buchan
  • 12,707
  • 2
  • 48
  • 55
3

Here is short Scala solution:

  def bfs(nodes: List[Node]): List[Node] = {
    if (nodes.nonEmpty) {
      nodes ++ bfs(nodes.flatMap(_.children))
    } else {
      List.empty
    }
  }

Idea of using return value as accumulator is well suited. Can be implemented in other languages in similar way, just make sure that your recursive function process list of nodes.

Test code listing (using @marco test tree):

import org.scalatest.FlatSpec

import scala.collection.mutable

class Node(val value: Int) {

  private val _children: mutable.ArrayBuffer[Node] = mutable.ArrayBuffer.empty

  def add(child: Node): Unit = _children += child

  def children = _children.toList

  override def toString: String = s"$value"
}

class BfsTestScala extends FlatSpec {

  //            1
  //          / | \
  //        2   3   4
  //      / |       | \
  //    5   6       7  8
  //  / |           | \
  // 9  10         11  12
  def tree(): Node = {
    val root = new Node(1)
    root.add(new Node(2))
    root.add(new Node(3))
    root.add(new Node(4))
    root.children(0).add(new Node(5))
    root.children(0).add(new Node(6))
    root.children(2).add(new Node(7))
    root.children(2).add(new Node(8))
    root.children(0).children(0).add(new Node(9))
    root.children(0).children(0).add(new Node(10))
    root.children(2).children(0).add(new Node(11))
    root.children(2).children(0).add(new Node(12))
    root
  }

  def bfs(nodes: List[Node]): List[Node] = {
    if (nodes.nonEmpty) {
      nodes ++ bfs(nodes.flatMap(_.children))
    } else {
      List.empty
    }
  }

  "BFS" should "work" in {
    println(bfs(List(tree())))
  }
}

Output:

List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
Ilya Bystrov
  • 2,902
  • 2
  • 14
  • 21
2

Here's a python implementation:

graph = {'A': ['B', 'C'],
         'B': ['C', 'D'],
         'C': ['D'],
         'D': ['C'],
         'E': ['F'],
         'F': ['C']}

def bfs(paths, goal):
    if not paths:
        raise StopIteration

    new_paths = []
    for path in paths:
        if path[-1] == goal:
            yield path

        last = path[-1]
        for neighbor in graph[last]:
            if neighbor not in path:
                new_paths.append(path + [neighbor])
    yield from bfs(new_paths, goal)


for path in bfs([['A']], 'D'):
    print(path)
rookie
  • 2,783
  • 5
  • 29
  • 43
2

Here's a Scala 2.11.4 implementation of recursive BFS. I've sacrificed tail-call optimization for brevity, but the TCOd version is very similar. See also @snv's post.

import scala.collection.immutable.Queue

object RecursiveBfs {
  def bfs[A](tree: Tree[A], target: A): Boolean = {
    bfs(Queue(tree), target)
  }

  private def bfs[A](forest: Queue[Tree[A]], target: A): Boolean = {
    forest.dequeueOption exists {
      case (E, tail) => bfs(tail, target)
      case (Node(value, _, _), _) if value == target => true
      case (Node(_, l, r), tail) => bfs(tail.enqueue(List(l, r)), target)
    }
  }

  sealed trait Tree[+A]
  case class Node[+A](data: A, left: Tree[A], right: Tree[A]) extends Tree[A]
  case object E extends Tree[Nothing]
}
Joffer
  • 1,921
  • 2
  • 21
  • 23
2

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])
1

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)
Ashok
  • 93
  • 1
  • 1
  • 9
  • I think this might get stuck in an infinite loop -- the vertices are being marked as visited, but they are never tested for visited-ness before recursing again. –  Feb 09 '16 at 17:43
  • This snippet is similar to DFS rather than BFS – Dení Aug 02 '17 at 05:13
1

BFS for a binary (or n-ary) tree can be done recursively without queues as follows (here in Java):

public class BreathFirst {

    static class Node {
        Node(int value) {
            this(value, 0);
        }
        Node(int value, int nChildren) {
            this.value = value;
            this.children = new Node[nChildren];
        }
        int value;
        Node[] children;
    }

    static void breathFirst(Node root, Consumer<? super Node> printer) {
        boolean keepGoing = true;
        for (int level = 0; keepGoing; level++) {
            keepGoing = breathFirst(root, printer, level);
        }
    }

    static boolean breathFirst(Node node, Consumer<? super Node> printer, int depth) {
        if (depth < 0 || node == null) return false;
        if (depth == 0) {
            printer.accept(node);
            return true;
        }
        boolean any = false;
        for (final Node child : node.children) {
            any |= breathFirst(child, printer, depth - 1);
        }
        return any;
    }
}

An example traversal printing numbers 1-12 in ascending order:

public static void main(String... args) {
    //            1
    //          / | \
    //        2   3   4
    //      / |       | \
    //    5   6       7  8
    //  / |           | \
    // 9  10         11  12

    Node root = new Node(1, 3);
    root.children[0] = new Node(2, 2);
    root.children[1] = new Node(3);
    root.children[2] = new Node(4, 2);
    root.children[0].children[0] = new Node(5, 2);
    root.children[0].children[1] = new Node(6);
    root.children[2].children[0] = new Node(7, 2);
    root.children[2].children[1] = new Node(8);
    root.children[0].children[0].children[0] = new Node(9);
    root.children[0].children[0].children[1] = new Node(10);
    root.children[2].children[0].children[0] = new Node(11);
    root.children[2].children[0].children[1] = new Node(12);

    breathFirst(root, n -> System.out.println(n.value));
}
marco
  • 711
  • 6
  • 14
1

From an adaptation of this question while studying on AlgoExpert. The following Class is provided already in the prompt. Here are iterative and recursive solutions in python. The goal of this problem is to return an output array which lists the name of the nodes in order visited. So if the order of traversal was A -> B -> D -> F the output is ['A','B','D','F']

class Node:
    def __init__(self, name):
        self.children = []
        self.name = name

    def addChild(self, name):
        self.children.append(Node(name))
        return self

Recursive

def breadthFirstSearch(self, array):
    return self._bfs(array, [self])
    
def _bfs(self, array, visited):

    # Base case - no more nodes to visit
    if len(visited) == 0:
        return array

    node = visited.pop(0)
    array.append(node.name)
    visited.extend(node.children)
    return self._bfs(array, visited)

Iterative

def breadthFirstSearch(self, array):
    array.append(self.name)
    queue = [self]
    while len(queue) > 0:
        node = queue.pop(0)
        for child in node.children:
            array.append(child.name)
            queue.append(child)
    return array
Adam Hughes
  • 14,601
  • 12
  • 83
  • 122
1

In addition to the excellent explanation in the top answer, I would add another possible solution without queues. It uses recursion and generators:

class TreeNode {
    constructor(
        public readonly value: number,
        public readonly children: TreeNode[] = [],
    ) {
    }
}

function* bfs(rootNode: TreeNode, recursionLevel: number = 0): Generator<TreeNode> {
    yield rootNode

    if (recursionLevel > 10) return;    // Stop excessive recursion using hard limit
    for (const node of bfs(rootNode, recursionLevel + 1)) {
        for (const child of node.children) {
            yield child
        }
    }
}

NOTE: For demonstration purposes, it always makes 10 recursive calls regardless of the tree depth. For a more advanced version, see below.

Test script:

const tree = new TreeNode(1, [
    new TreeNode(11, [
        new TreeNode(111),
        new TreeNode(112),
        new TreeNode(113, [
            new TreeNode(1131),
        ]),
    ]),
    new TreeNode(12, [
        new TreeNode(121),
        new TreeNode(122, [
            new TreeNode(1221),
        ]),
    ]),
    new TreeNode(13, [
        new TreeNode(131),
    ]),
]);

for (const node of bfs(tree)) {
    console.log(node.value);
}

Output:

1
11
12
13
111
112
113
121
122
131
1131
1221

A more advanced version involves stopping recursion depending on the levels visited. For example:

let maxWalkLevel = 0;

function* bfs(rootNode: TreeNode, recursionLevel: number = 0): Generator<[number, TreeNode]> {
    yield [0, rootNode];

    if (recursionLevel > maxWalkLevel) return;   // Stop excessive recursion

    for (const [walkLevel, node] of bfs(rootNode, recursionLevel + 1)) {
        for (const child of node.children) {
            maxWalkLevel = Math.max(maxWalkLevel, walkLevel + 1);
            yield [walkLevel + 1, child]
        }
    }
}

Output:

0 - 1
1 - 11
1 - 12
1 - 13
2 - 111
2 - 112
2 - 113
2 - 121
2 - 122
2 - 131
3 - 1131
3 - 1221
IStranger
  • 1,868
  • 15
  • 23
1

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;
}
Justin
  • 4,196
  • 4
  • 24
  • 48
  • 2
    For other viewers: this is an example of implementing a ***complete*** tree in an array; Specifically, @Justin is doing a pre-order traversal, during which he saves node values (in BFS order) in an array at the appropriate BFS index. This allows the calling function to iterate linearly through the array, printing values in the BFS order. See this [general description](http://webdocs.cs.ualberta.ca/~holte/T26/tree-as-array.html) Note: the calling function must handle the case of non-complete trees. – bunkerdive Aug 06 '14 at 00:17
0
#include <bits/stdc++.h>
using namespace std;
#define Max 1000

vector <int> adj[Max];
bool visited[Max];

void bfs_recursion_utils(queue<int>& Q) {
    while(!Q.empty()) {
        int u = Q.front();
        visited[u] = true;
        cout << u << endl;
        Q.pop();
        for(int i = 0; i < (int)adj[u].size(); ++i) {
            int v = adj[u][i];
            if(!visited[v])
                Q.push(v), visited[v] = true;
        }
        bfs_recursion_utils(Q);
    }
}

void bfs_recursion(int source, queue <int>& Q) {
    memset(visited, false, sizeof visited);
    Q.push(source);
    bfs_recursion_utils(Q);
}

int main(void) {
    queue <int> Q;
    adj[1].push_back(2);
    adj[1].push_back(3);
    adj[1].push_back(4);

    adj[2].push_back(5);
    adj[2].push_back(6);

    adj[3].push_back(7);

    bfs_recursion(1, Q);
    return 0;
}
Kaidul
  • 15,409
  • 15
  • 81
  • 150
0

Here is a JavaScript Implementation that fakes Breadth First Traversal with Depth First recursion. I'm storing the node values at each depth inside an array, inside of a hash. If a level already exists(we have a collision), so we just push to the array at that level. You could use an array instead of a JavaScript object as well since our levels are numeric and can serve as array indices. You can return nodes, values, convert to a Linked List, or whatever you want. I'm just returning values for the sake of simplicity.

BinarySearchTree.prototype.breadthFirstRec = function() {

    var levels = {};

    var traverse = function(current, depth) {
        if (!current) return null;
        if (!levels[depth]) levels[depth] = [current.value];
        else levels[depth].push(current.value);
        traverse(current.left, depth + 1);
        traverse(current.right, depth + 1);
    };

    traverse(this.root, 0);
    return levels;
};


var bst = new BinarySearchTree();
bst.add(20, 22, 8, 4, 12, 10, 14, 24);
console.log('Recursive Breadth First: ', bst.breadthFirstRec());
/*Recursive Breadth First:  
{ '0': [ 20 ],
  '1': [ 8, 22 ],
  '2': [ 4, 12, 24 ],
  '3': [ 10, 14 ] } */

Here is an example of actual Breadth First Traversal using an iterative approach.

BinarySearchTree.prototype.breadthFirst = function() {

    var result = '',
        queue = [],
        current = this.root;

    if (!current) return null;
    queue.push(current);

    while (current = queue.shift()) {
        result += current.value + ' ';
        current.left && queue.push(current.left);
        current.right && queue.push(current.right);
    }
    return result;
};

console.log('Breadth First: ', bst.breadthFirst());
//Breadth First:  20 8 22 4 12 24 10 14
Alex Hawkins
  • 616
  • 7
  • 10
0

Following is my code for completely recursive implementation of breadth-first-search of a bidirectional graph without using loop and queue.



public class Graph
{
    public int V;   
    public LinkedList<Integer> adj[];

    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList<>();
    }

    void addEdge(int v,int w)
    {
        adj[v].add(w);
        adj[w].add(v);
    }

    public LinkedList<Integer> getAdjVerted(int vertex)
    {
        return adj[vertex];
    }

    public String toString()
    {
        String s = "";

        for (int i=0;i<adj.length;i++)
        {
            s = s +"\n"+i +"-->"+ adj[i] ;
        }
        return s;
    }
}

//BFS IMPLEMENTATION

public static void recursiveBFS(Graph graph, int vertex,boolean visited[], boolean isAdjPrinted[])
    {
        if (!visited[vertex])
        {
            System.out.print(vertex +" ");
            visited[vertex] = true;
        }

        if(!isAdjPrinted[vertex])
        {
            isAdjPrinted[vertex] = true;
            List<Integer> adjList = graph.getAdjVerted(vertex);
            printAdjecent(graph, adjList, visited, 0,isAdjPrinted);
        }
    }

    public static void recursiveBFS(Graph graph, List<Integer> vertexList, boolean visited[], int i, boolean isAdjPrinted[])
    {
        if (i < vertexList.size())
        {
            recursiveBFS(graph, vertexList.get(i), visited, isAdjPrinted);
            recursiveBFS(graph, vertexList, visited, i+1, isAdjPrinted);
        }
    }

    public static void printAdjecent(Graph graph, List<Integer> list, boolean visited[], int i, boolean isAdjPrinted[])
    {
        if (i < list.size())
        {
            if (!visited[list.get(i)])
            {
                System.out.print(list.get(i)+" ");
                visited[list.get(i)] = true;
            }
            printAdjecent(graph, list, visited, i+1, isAdjPrinted);
        }
        else
        {
            recursiveBFS(graph, list, visited, 0, isAdjPrinted);
        }
    }

Pushkal
  • 13
  • 7
0

C# implementation of recursive breadth-first search algorithm for a binary tree.

Binary tree data visualization

IDictionary<string, string[]> graph = new Dictionary<string, string[]> {
    {"A", new [] {"B", "C"}},
    {"B", new [] {"D", "E"}},
    {"C", new [] {"F", "G"}},
    {"E", new [] {"H"}}
};

void Main()
{
    var pathFound = BreadthFirstSearch("A", "H", new string[0]);
    Console.WriteLine(pathFound); // [A, B, E, H]

    var pathNotFound = BreadthFirstSearch("A", "Z", new string[0]);
    Console.WriteLine(pathNotFound); // []
}

IEnumerable<string> BreadthFirstSearch(string start, string end, IEnumerable<string> path)
{
    if (start == end)
    {
        return path.Concat(new[] { end });
    }

    if (!graph.ContainsKey(start)) { return new string[0]; }    

    return graph[start].SelectMany(letter => BreadthFirstSearch(letter, end, path.Concat(new[] { start })));
}

If you want algorithm to work not only with binary-tree but with graphs what can have two and more nodes that points to same another node you must to avoid self-cycling by holding list of already visited nodes. Implementation may be looks like this.

Graph data visualization

IDictionary<string, string[]> graph = new Dictionary<string, string[]> {
    {"A", new [] {"B", "C"}},
    {"B", new [] {"D", "E"}},
    {"C", new [] {"F", "G", "E"}},
    {"E", new [] {"H"}}
};

void Main()
{
    var pathFound = BreadthFirstSearch("A", "H", new string[0], new List<string>());
    Console.WriteLine(pathFound); // [A, B, E, H]

    var pathNotFound = BreadthFirstSearch("A", "Z", new string[0], new List<string>());
    Console.WriteLine(pathNotFound); // []
}

IEnumerable<string> BreadthFirstSearch(string start, string end, IEnumerable<string> path, IList<string> visited)
{
    if (start == end)
    {
        return path.Concat(new[] { end });
    }

    if (!graph.ContainsKey(start)) { return new string[0]; }


    return graph[start].Aggregate(new string[0], (acc, letter) =>
    {
        if (visited.Contains(letter))
        {
            return acc;
        }

        visited.Add(letter);

        var result = BreadthFirstSearch(letter, end, path.Concat(new[] { start }), visited);
        return acc.Concat(result).ToArray();
    });
}
0

I have made a program using c++ which is working in joint and disjoint graph too .

    #include <queue>
#include "iostream"
#include "vector"
#include "queue"

using namespace std;

struct Edge {
    int source,destination;
};

class Graph{
    int V;
    vector<vector<int>> adjList;
public:

    Graph(vector<Edge> edges,int V){
        this->V = V;
        adjList.resize(V);
        for(auto i : edges){
            adjList[i.source].push_back(i.destination);
            //     adjList[i.destination].push_back(i.source);
        }
    }
    void BFSRecursivelyJoinandDisjointtGraphUtil(vector<bool> &discovered, queue<int> &q);
    void BFSRecursivelyJointandDisjointGraph(int s);
    void printGraph();


};

void Graph :: printGraph()
{
    for (int i = 0; i < this->adjList.size(); i++)
    {
        cout << i << " -- ";
        for (int v : this->adjList[i])
            cout <<"->"<< v << " ";
        cout << endl;
    }
}


void Graph ::BFSRecursivelyJoinandDisjointtGraphUtil(vector<bool> &discovered, queue<int> &q) {
    if (q.empty())
        return;
    int v = q.front();
    q.pop();
    cout << v <<" ";
    for (int u : this->adjList[v])
    {
        if (!discovered[u])
        {
            discovered[u] = true;
            q.push(u);
        }
    }
    BFSRecursivelyJoinandDisjointtGraphUtil(discovered, q);

}

void Graph ::BFSRecursivelyJointandDisjointGraph(int s) {
    vector<bool> discovered(V, false);
    queue<int> q;

    for (int i = s; i < V; i++) {
        if (discovered[i] == false)
        {
            discovered[i] = true;
            q.push(i);
            BFSRecursivelyJoinandDisjointtGraphUtil(discovered, q);
        }
    }
}

int main()
{

    vector<Edge> edges =
            {
                    {0, 1}, {0, 2}, {1, 2}, {2, 0}, {2,3},{3,3}
            };

    int V = 4;
    Graph graph(edges, V);
 //   graph.printGraph();
    graph.BFSRecursivelyJointandDisjointGraph(2);
    cout << "\n";




    edges = {
            {0,4},{1,2},{1,3},{1,4},{2,3},{3,4}
    };

    Graph graph2(edges,5);

    graph2.BFSRecursivelyJointandDisjointGraph(0);
    return 0;
}
arpansahu
  • 41
  • 1
  • 4
0

I think this can be done using pointers, without using any QUEUE.

Basically we are maintaining two pointers at any point, one is pointing to the parents, the other is pointing to the children to be processed ( linkedlist to all which have been processed )

Now you simply assign the pointer of the child & when parent processing finishes you just make the child to be parent for processing next level

following is my code :

//Tree Node
struct Node {
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
    

//Algorightm :

    void LevelTraverse(Node* parent,Node* chidstart,Node* childend ){
        if(!parent && !chidstart) return;  // we processed everything
        
        if(!parent && chidstart){ //finished processing last level
            parent=chidstart;chidstart=childend=NULL; // assgin child to parent for processing next level
            LevelTraverse(parent,chidstart,childend);
        }else if(parent && !chidstart){ // This is new level first node tobe processed
            Node* temp=parent; parent=parent->next;
            if(temp->left) { childend=chidstart=temp->left; }
            if(chidstart){
                if(temp->right) { childend->next=temp->right; childend=temp->right; }
            }else{
                if(temp->right) { childend=chidstart=temp->right; }
            }
            LevelTraverse(parent,chidstart,childend);
        }else if(parent && chidstart){ //we are in mid of some level processing
            Node* temp=parent; parent=parent->next;
            if(temp->left) { childend->next=temp->left; childend=temp->left; }
            if(temp->right) { childend->next=temp->right; childend=temp->right; }
            LevelTraverse(parent,chidstart,childend);
        }
    }

//Driver code :

    Node* connect(Node* root) {
        if(!root) return NULL;
        Node* parent; Node* childs, *childe; parent=childs=childe=NULL;
        parent=root;
        LevelTraverse(parent, childs, childe);
        return root;
    }
AnotherDeveloper
  • 2,161
  • 2
  • 23
  • 27