7

I was wondering if it's possible to print a binary tree in breadth first order while using only O(1) space?

The difficult part is that one have to use additional space to memorize the next level to traverse, and that grows with n.

Since we haven't place any limitation on the time part, maybe there are some inefficient (in terms of time) ways that can achieve this?

Any idea?

vgru
  • 49,838
  • 16
  • 120
  • 201
clwen
  • 20,004
  • 31
  • 77
  • 94

4 Answers4

4

This is going to depend on some finer-grained definitions, for example if the edges have back-links. Then it's easy, because you can just follow a back link up the tree. Otherwise I can't think off hand of a way to do it without O(lg number of nodes) space, because you need to remember at least the nodes "above".

Update

Oh wait, of course it can be done in O(1) space with a space time trade. Everywhere you would want to do a back link, you save your place and do BFS, tracking the most recent node, until you find yours. Then back up to the most recently visited node and proceed.

Problem is, that's O(1) space but O(n^2) time.

Another update

Let's assume that we've reached node n_i, and we want to reach the parent of that node, which we'll call wlg n_j. We have identified the distinguished root node n_0.

Modify the breath-first search algorithm so that when it follows a directed edge (n_x,n_y), the efferent or "incoming" node is stored. Thus when you follow (n_x,n_y), you save n_x.

When you start the BFS again from n_0, you are guaranteed (assuming it really is a tree) that at SOME point, you will transition the edge (n_j,n_i). At that point you observe you're back at n_i. You've stored n_j and so you know the reverse edge is (n_i,n_j).

Thus, you get that single backtrack with only two extra cells, one for n_0 and one for the "saved" node. This is O(1)

I'm not so sure of O(n^2) -- it's late and it's been a hard day so I don't want to compose a proof. I'm sure it's O((|N|+|E|)^2) where |N| and |E| are the size of the sets of vertices and edges respectively.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • I suppose no back-links is involved, or the question would be trivial. – clwen Nov 07 '11 at 16:25
  • I'm not familiar with this IDDFS mentioned below, but if it works as advertised, that's a little better, O(lg lg #nodes). – Charlie Martin Nov 07 '11 at 16:31
  • 1
    @CharlieMartin: could you elaborate the second example a bit more? If you need to use BFS for each backlink, and for each backlink in that BFS also use a BFS, it seems like you will need more than O(1) space? – vgru Nov 08 '11 at 08:37
  • 1
    I still don't understand how this should work. Let's say you are 20 levels deep in your hierarchy at one point, and you need to backtrack back to 19th level. How can you "start the BFS again" and "at some point transition the edge" if all you have is an incoming node for a node in 20th level? What about all the other nodes you need to traverse before getting here? Consider [this Wikipedia image](http://en.wikipedia.org/wiki/File:Animated_BFS.gif), for example: you are at node "e" currently. How would your algorithm know that the next node to be printed is "f"? – vgru Jan 23 '12 at 18:03
  • You know where the root node is, no? If you don't, then change the algorithm to save the root node when you start; that adds only a constant amount of space, so it's still O(1). Now, every time you want to "backtrack", you start from the root node. You're guaranteed to find the node you're at again eventually (otherwise how'd you get there the first time?). – Charlie Martin Jan 24 '12 at 19:13
  • That's actually in the answer BTW -- the distinguished node n_0 is the root. – Charlie Martin Jan 24 '12 at 19:14
  • On the E-F question, look at your BFS algorithm: it must *somehow* know it goes to F next if you're at E, right? – Charlie Martin Jan 24 '12 at 19:17
2

An interesting special case is heaps.

From heapq docs:

Heaps are binary trees for which every parent node has a value less than or equal to any of its children. This implementation uses arrays for which heap[k] <= heap[2*k+1] and heap[k] <= heap[2*k+2] for all k, counting elements from zero. For the sake of comparison, non-existing elements are considered to be infinite. The interesting property of a heap is that its smallest element is always the root, heap[0]. [explanation by François Pinard]

How a tree represented in memory (indexes of the array):

                               0

              1                                 2

      3               4                5               6

  7       8       9       10      11      12      13      14

15 16   17 18   19 20   21 22   23 24   25 26   27 28   29 30

In this case nodes in the array are already stored in a breadth first order.

for value in the_heap:
    print(value)

O(1) in space.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
1

I know that this is strictly not an answer to the question, but visiting the nodes of a tree in breadth-first order can be done using O(d) space, where d is the depth of the tree, by a recursive iterative deepening depth first search (IDDFS). The space is required for the stack, of course. In the case of a balanced tree, d = O(lg n) where n is the number of nodes. I honestly don't see how you'd do it in constant space without the backlinks suggested by @Charlie Martin.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
-1

It is easy to implement a recursive method to get all the nodes of a tree at a given level. Hence, we could calculate the height of the tree and get all the nodes and each level. This is Level Order Traversal of the tree. But, the time complexity is O(n^2). Below is the Java implementation (source).

class Node 
{ 
    int data; 
    Node left, right; 
    public Node(int item) 
    { 
        data = item; 
        left = right = null; 
    } 
} 

class BinaryTree 
{ 
    Node root; 

    public BinaryTree() 
    { 
        root = null; 
    } 

    void PrintLevelOrder() 
    { 
        int h = height(root); 
        int i; 
        for (i=1; i<=h; i++) 
            printGivenLevel(root, i); 
    } 

    int Height(Node root) 
    { 
        if (root == null) 
           return 0; 
        else
        { 
            int lheight = height(root.left); 
            int rheight = height(root.right); 

        } 
    } 

    void PrintGivenLevel (Node root ,int level) 
    { 
        if (root == null) 
            return; 
        if (level == 1) 
            System.out.print(root.data + " "); 
        else if (level > 1) 
        { 
            printGivenLevel(root.left, level-1); 
            printGivenLevel(root.right, level-1); 
        } 
    }
}
havij
  • 1,030
  • 14
  • 29
  • This uses O(*h*) space where *h* is the height of the tree. The recursion is implemented using a call stack, which counts as auxiliary space. – kaya3 Nov 15 '19 at 05:33