How to print a binary tree level by level? Interview question! - algorithm

How to print a binary tree level by level?
This is an interview question I got today. Sure enough, using a BFS style would definitely work. However, the follow up question is: How to print the tree using constant memory? (So no queue can be used)
I thought of converting the binary tree into a linked list somehow but have not come up with a concrete solution.
Any suggestions?
Thanks

One way to avoid using extra memory (much extra, anyway) is to manipulate the tree as you traverse it -- as you traverse downward through nodes, you make a copy of its pointer to one of the children, then reverse that to point back to the parent. When you've gotten to the bottom, you follow the links back up to the parents, and as you go you reverse them to point back to the children.
Of course, that's not the whole job, but it's probably the single "trickiest" part.

Extending on what Jerry Coffin said, I had asked a question earlier about doing something similar using in-order traversal. It uses the same logic as explained by him.
Check it out here:
Explain Morris inorder tree traversal without using stacks or recursion

You can do it by repeatedly doing an in-order traversal of the tree while printing only those nodes at the specified level. However, this isn't strictly constant memory since recursion uses the call stack. And it's super inefficient. Like O(n * 2^n) or something.
printLevel = 1;
while(moreLevels) {
moreLevels = printLevel(root, 1, printLevel);
printLevel++;
}
boolean printLevel(Node node, int currentLevel, int printLevel) {
boolean moreLevels = false;
if(node == null) {
return(false);
}
else if(currentLevel == printLevel) {
print the node value;
}
else {
moreLevels |= printLevel(node.leftChild, currentLevel + 1, printLevel);
moreLevels |= printLevel(node.rightChild, currentLevel + 1, printLevel);
}
return(moreLevels);
}

Related

Cracking the Coding Interview - Example 9 (Runtime Example)

This question is related to the depth of binary search tree, but my question is regarding of understanding the example code that is shown below:
int sum(Node node) {
if (node == null){
return 0;
}
return sum (node.left) + node.value + sum(node.right);
}
The author said the depth of this is roughly log N, I am not sure how to get log N.
Also, my understanding of this code, it seems to be a infinite one. I know it is not, but I can not convince myself. For example, if this is 1~3 array, the node start # 2, so:
LVL 1:sum(1)+2+sum(3)
LVL 2:sum(sum(0)+1+sum(2))+2+sum(sum(2)+3+sum(0))
LVL 3: ... (The sum(2) will repeat the LVL 1, and it will never end)
Anyone can help me point out the issue?
Thank you!
Decided to turn my comment into an answer:
Binary trees are log n as you keep cutting it in half each time, but this is for a balanced tree. A very unbalanced one would be O(N) if everything was on the right, for example.
So, why is it not infinite?
Since this is recursive it needs a way to stop calling itself, and that is when node is null, then it bails out.
So, in every tree you will eventually reach child nodes that aren't set, and these will stop the recursion, which prevents it from being infinite.
If you remove that if statement then you will get an exception, but in a recursive algorithm that is actually doing something that won't end you would get a stack overflow.

Rebalancing an arbitrary BST?

Reference:
I was asked this question #MS SDE interview, 3rd round. And it's not a homework problem. I also gave it a thought and mentioning my approach below.
Question:
Modify a BST so that it becomes as balanced as possible. Needless to mention, you should do it as efficient as possible.
Hint:
Interviewer said that this is a logical question, if you think differently you will get the answer. No difficult coding involved.
--> Having said that, I do not think he was expecting me to point to AVL/RB Trees.
My Solution:
I proposed that, I would do inorder traversal of tree, take middle element as root of new tree(lets call it new root). Then go to the left part of middle element, take its middle element as root of left subtree of tree rooted new root. Similarly do for right part.
Doing this recursively will give the optimal balanced BST.
Why I am posting it here:
But he was not satisfied with the answer :( So, is there really a way of doing this w/o going for weights/RB coloring strategy, or was he just fooling around with me?
Please put in your expert thoughts.
Duplicate? No!
I know there is this question but the solution proposed by requester is too complicated, and other one talks about AVL trees.
You might want to look into the Day-Stout-Warren algorithm, which is an O(n)-time, O(1)-space algorithm for reshaping an arbitrary binary search tree into a complete binary tree. Intuitively, the algorithm works as follows:
Using tree rotations, convert the tree into a degenerate linked list.
By applying selective rotations to the linked list, convert the list back into a completely balanced tree.
The beauty of this algorithm is that it runs in linear time and requires only constant memory overhead; in fact, it just reshapes the underlying tree, rather than creating a new tree and copying over the old data. It is also relatively simple to code up.
Hope this helps!
"Balanced as possible" = complete (or full) binary tree1. You cannot get more balanced that it.
The solution is simple - build an "empty" complete binary tree, and iterate the new tree and the input tree (simultaneously) in inorder-traversal to fill the complete tree.
When you are done, you have the most balanced tree you can get, and time complexity of this approach is O(n).
EDIT:
This should be done following these steps:
Build a dummy complete tree with n nodes. All the values to each
node will be initialized to some garbage value.
Create two iterators: (1) originalIter for the original tree, (2) newIter for the new (initialized with garbage) tree. Both iterators will return elements in in-order traversal.
Do the following to fill the tree with the values from the original:
while (originalIter.hasNext()):
newIter.next().value = originalIter.next().value
(1) (From Wikipedia): A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible
The DSW algorithm can solve this is O(n) time. The algorithm goes as follows:
1] Using right-rotation operations, turn the tree into a linked list
(a.k.a. backbone or vine)
2] Rotate every second node of the backbone about its parent to turn
the backbone into a perfectly balanced BST.
Reference
This will convert your normal BST into a balanced BST with minimum possible height in O(n). First, save all your nodes sorted into a vector. Then, the root is the mid element and recursively build a tree from 0 to mid-1 as its left and build a tree from mid+1 to vector.size()-1 as its right child. After all these steps root keeps the balanced BST with the min-height.
import java.util.Vector;
public class ConvertBSTIntoBalanced {
public static void main(String[] args) {
TreeNode node1 = new TreeNode(1);
TreeNode node2 = new TreeNode(2);
TreeNode node3 = new TreeNode(3);
TreeNode node4 = new TreeNode(4);
node1.right = node2;
node2.right = node3;
node3.right = node4;
ConvertBSTIntoBalanced convertBSTIntoBalanced = new ConvertBSTIntoBalanced();
TreeNode balancedBSTRoot = convertBSTIntoBalanced.balanceBST(node1);
}
private void saveNodes(TreeNode node, Vector<TreeNode> nodes) {
if (node == null)
return;
saveNodes(node.left, nodes);
nodes.add(node);
saveNodes(node.right, nodes);
}
private TreeNode buildTree(Vector<TreeNode> nodes, int start, int end) {
if (start > end)
return null;
int mid = (start + end) / 2;
TreeNode midNode = nodes.get(mid);
midNode.left = buildTree(nodes, start, mid - 1);
midNode.right = buildTree(nodes, mid + 1, end);
return midNode;
}
public TreeNode balanceBST(TreeNode root) {
Vector<TreeNode> nodes = new Vector<>();
saveNodes(root, nodes);
return buildTree(nodes, 0, nodes.size() - 1);
}
public class TreeNode {
public Integer val;
public TreeNode left;
public TreeNode right;
public TreeNode(Integer x) {
val = x;
}
}
}
I hope it helps.

Converting a iterative algorithm to recursive

I have writing a code to print the tree in Level Order using a queue(Array).
void printLevelOrder(node *root) {
node* queue[10];
node*t=root;
int y=0;
queue[y]=t;
for(int i=0;i<10;i++)
{
printf("%d,",queue[i]->val);
t=queue[i];
if((t->left)!=NULL){
queue[++y]=t->left;
}
if((t->right)!=NULL){
queue[++y]=t->right;
}
}
}
I want to convert the method into a recursive method.
I tried but I am not getting the correct solution. Is it possible to convert this type of problem to using recursive calls?
It is possible to make this recursive, but in this case the result would probably look like the body of the loop in the code above executing and then calling itself for the next element in the queue. It is not possible to convert this into a kind of recursion more often found in tree traversal algorithms, where the recursive method invokes itself for the child nodes of the one it received as an argument. There is thus no performance gain to expect -- you'll still need the queue or some structure like this -- and I don't really see the point in performing the conversion.
I am not sure if this is what you were looking for but it is partial recursion.
void print_level_part(node* p, level) {
if(p) {
if(level==1) {
printf("%d", p->val);
} else {
print_level_part(p->left, level-1);
print_level_part(p->right, level-1);
}
}
}
//the loop in main which does the main printing.
for(int i=0; i<n; ++i) {
print_level_part(root, i);
}
If you want completely recursive solution then I may suggest that you change the for loop in main a recursive function.
This is an example of what Qnan was talking about:
void printNext(node **queue,int i,int y)
{
if (i==y) return;
node *t = queue[i++];
printf("%d,",t->val);
if (t->left) queue[y++] = t->left;
if (t->right) queue[y++] = t->right;
printNext(queue,i,y);
}
void printLevelOrder(node *root)
{
node *queue[10]; /* be careful with hard-coded queue size! */
int y=0, i=0;
queue[y++]=root;
printNext(queue,i,y);
printf("\n");
}
As far as I understand, printing a tree in "Level Order" is actually a BFS traversal of the given tree, for which the recursion is not suited. Recursion is a well-suited approach to DFS.
The recursion internally works with a stack (a LIFO structure), while BFS uses a queue (a FIFO structure). A tree algorithm is suitable for recursion if the solution for a root depends on (the results, or just traversal order) the solutions for the subtrees. Recursion goes to the "bottom" of the tree, and solves the problem from bottom upwards. From this, pre-order, in-order and post-order traversals can be done as recursions:
pre-order : print the root, print the left subtree, print the right subtree
in-order : print the left subtree, print the root, print the right subtree
post-order: print the left subtree, print the right subtree, print the root
Level-order, however, can not be decomposed in "do something for the root, do something for each of the subtrees". The only possible "recursive" implementation would follow #Qnan suggestion, and, as he said, would not make much sense.
What is possible, however, is to transform any recursive algorithm in to an iterative one fairly elegantly. Since the internal recursion actually works with a stack, the only trick in this situation would be to use your own stack instead of the system one. Some of the slight differences between this kind of recursive and iterative implementation would be:
with iterative, you save time on function calls
with recursive, you usually get a more intuitive code
with recursive, extra memory gets allocated for a return address with each function call
with iterative, you allocate the memory, and you determine where the memory is allocated

How to find the rank of a node in an AVL tree?

I need to implement two rank queries [rank(k) and select(r)]. But before I can start on this, I need to figure out how the two functions work.
As far as I know, rank(k) returns the rank of a given key k, and select(r) returns the key of a given rank r.
So my questions are:
1.) How do you calculate the rank of a node in an AVL(self balancing BST)?
2.) Is it possible for more than one key to have the same rank? And if so, what woulud select(r) return?
I'm going to include a sample AVL tree which you can refer to if it helps answer the question.
Thanks!
Your question really boils down to: "how is the term 'rank' normally defined with respect to an AVL tree?" (and, possibly, how is 'select' normally defined as well).
At least as I've seen the term used, "rank" means the position among the nodes in the tree -- i.e., how many nodes are to its left. You're typically given a pointer to a node (or perhaps a key value) and you need to count the number of nodes to its left.
"Select" is basically the opposite -- you're given a particular rank, and need to retrieve a pointer to the specified node (or the key for that node).
Two notes: First, since neither of these modifies the tree at all, it makes no real difference what form of balancing is used (e.g., AVL vs. red/black); for that matter a tree with no balancing at all is equivalent as well. Second, if you need to do this frequently, you can improve speed considerably by adding an extra field to each node recording how many nodes are to its left.
Rank is the number of nodes in the Left sub tree plus one, and is calculated for every node. I believe rank is not a concept specific to AVL trees - it can be calculated for any binary tree.
Select is just opposite to rank. A rank is given and you have to return a node matching that rank.
The following code will perform rank calculation:
void InitRank(struct TreeNode *Node)
{
if(!Node)
{
return;
}
else
{ Node->rank = 1 + NumeberofNodeInTree(Node->LChild);
InitRank(Node->LChild);
InitRank(Node->RChild);
}
}
int NumeberofNodeInTree(struct TreeNode *Node)
{
if(!Node)
{
return 0;
}
else
{
return(1+NumeberofNodeInTree(Node->LChild)+NumeberofNodeInTree(Node->RChild));
}
}
Here is the code i wrote and worked fine for AVL Tree to get the rank of a particular value. difference is just you used a node as parameter and i used a key a parameter. you can modify this as your own way. Sample code:
public int rank(int data){
return rank(data,root);
}
private int rank(int data, AVLNode r){
int rank=1;
while(r != null){
if(data<r.data)
r = r.left;
else if(data > r.data){
rank += 1+ countNodes(r.left);
r = r.right;
}
else{
r.rank=rank+countNodes(r.left);
return r.rank;
}
}
return 0;
}
[N.B] If you want to start your rank from 0 then initialize variable rank=0.
you definitely should have implemented the method countNodes() to execute this code.

Homework: binary tree - level-order trasversal

is there a way to visit a binary tree from the lowest level to the higher (root) ?
not from the root-level to the lowest!!!
(and not using the level-order traversal and a stack...!!!) <--- its opposite..
so difficult...thank you!
There's a few challenges here that lead to different solutions:
Can you traverse up the tree? Often data structures are set up so you can only go down. You could find all leaf nodes, put them in a priority queue by level, and then traverse up.
Can you store O(n) additional data? You could traverse it in a normal breadth-first manner, inserting pointers into a priority queue by level, as with the previous solution, but this time inserting all nodes during the initial traversal. This will increase the maximum size of the auxiliary data used during traversal though.
Is the tree guaranteed to be balanced and full, like it might be in a Heap-like tree? If it is, you can traverse it in a simpler manner, by just going to the right places.
You probably could do it easily IF you maintained a pointer to the node at the greatest depth. If you don't, then you must find that node before begining your traversal. Also, your nodes will all have to have pointers to their parents.
I explain in a better way. I have an algebraic expression tree (so not balanced). I have to valuate it USING a queue (and only a queue). I asked this question because I think the only way is to take nodes starting from the lowest level, till the root...
example:
tree ( + ( * ( 2 ) ( 2 ) ) ( 3 ) )
I take the queue and:
enqueue(1);
enqueue(2);
(*) -----> dequeue; dequeue; result = 2 * 2; enqueue(result);
enqueue 3;
(+) -----> dequeue; dequeue; result = 4 + 3; give result;
so I need to have this traversal: 2 ; 2 ; * ; 3 ; +
I dont know if it's clear...
Provided I understood you question correctly: If you want to traverse the tree visiting a leaf first and the root last, you can visit the nodes on the way back as you traverse the tree.
function traverse(node)
for each child of node
traverse(child)
end
visit(node)
end
If you want to visit the nodes in level order, you could do something like this (though using a stack -- I'm not sure whether you didn't want one at all or some particular solution using a stack):
queue.push(root)
while queue is not empty
node = queue.pop()
for each child of node
queue.push(child)
stack.push(child)
end
end
while stack is not empty
visit(stack.pop())
end
You can do it using only a queue, but with worse time complexity, if you do it like this:
for i = treedepth down to 0
queue.push(root)
while queue is not empty
node = queue.pop()
if node has depth i
visit(node)
else
for each child of node
queue.push(child)
end
end
end
end
The tree depth and node levels can be found using an initial traversal, if needed.
However, if you are allowed to make recursive calls, you actually have access to a stack (the call stack). This can be exploited to implement the second solution, but making the stack implicit.
function unwind(queue)
if queue is not empty
node = queue.pop()
unwind(queue)
visit(node)
end
end
queue.push(root)
while queue is not empty
node = queue.pop()
for each child of node
queue.push(child)
queue2.push(child)
end
end
unwind(queue2)
And of course, if you have access to almost any other data structure (list, array, priority queue, double ended queue, etc.) you can easily implement a stack yourself. But then it would be rather pointless to forbid stacks in the first place.
Queue is only useful for traversing level-order from root to leaf of the tree.
You can use a Depth-first Traversal for printing a certain level.
Like this:
void printLevel(BinaryTree *p, int level) {
if (!p) return;
if (level == 1) {
cout << p->data << " ";
} else {
printLevel(p->left, level-1);
printLevel(p->right, level-1);
}
}
To print all levels from leaf up to root, you would need to find the maximum depth of the tree. This could be done easily using depth-first traversal as well (You can easily google the solution).
void printLevelOrder(BinaryTree *root) {
int height = maxHeight(root);
for (int level = height; level >= 1; level--) {
printLevel(root, level);
cout << endl;
}
}
The run time complexity is surprisingly, O(N), where N is the total number of nodes.
For more information and run-time complexity analysis, refer to the page below:
http://www.ihas1337code.com/2010/09/binary-tree-level-order-traversal-using_17.html

Resources