binary tree -print the elements according to the level - c++

This question was asked to me in an interview:
lets say we have above binary tree,how can i produce an output like below
2 7 5 2 6 9 5 11 4
i answered like may be we can have a level count variable and print all the elements sequentially by checking the level count variable of each node.
probably i was wrong.
can anybody give anyidea as to how we can achieve that?

You need to do a breadth first traversal of the tree. Here it is described as follows:
Breadth-first traversal: Depth-first
is not the only way to go through the
elements of a tree. Another way is to
go through them level-by-level.
For example, each element exists at a
certain level (or depth) in the tree:
tree
----
j <-- level 0
/ \
f k <-- level 1
/ \ \
a h z <-- level 2
\
d <-- level 3
people like to number things starting
with 0.)
So, if we want to visit the elements
level-by-level (and left-to-right, as
usual), we would start at level 0 with
j, then go to level 1 for f and k,
then go to level 2 for a, h and z, and
finally go to level 3 for d.
This level-by-level traversal is
called a breadth-first traversal
because we explore the breadth, i.e.,
full width of the tree at a given
level, before going deeper.

The traversal in your question is called a level-order traversal and this is how it's done (very simple/clean code snippet I found).
You basically use a queue and the order of operations will look something like this:
enqueue F
dequeue F
enqueue B G
dequeue B
enqueue A D
dequeue G
enqueue I
dequeue A
dequeue D
enqueue C E
dequeue I
enqueue H
dequeue C
dequeue E
dequeue H
For this tree (straight from Wikipedia):

The term for that is level-order traversal. Wikipedia describes an algorithm for that using a queue:
levelorder(root)
q = empty queue
q.enqueue(root)
while not q.empty do
node := q.dequeue()
visit(node)
if node.left ≠ null
q.enqueue(node.left)
if node.right ≠ null
q.enqueue(node.right)

BFS:
std::queue<Node const *> q;
q.push(&root);
while (!q.empty()) {
Node const *n = q.front();
q.pop();
std::cout << n->data << std::endl;
if (n->left)
q.push(n->left);
if (n->right)
q.push(n->right);
}
Iterative deepening would also work and saves memory use, but at the expense of computing time.

If we are able to fetch the next element at same level, we are done. As per our prior knowledge, we can access these element using breadth first traversal.
Now only problem is how to check if we are at last element at any level. For this reason, we should be appending a delimiter (NULL in this case) to mark end of a level.
Algorithm:
1. Put root in queue.
2. Put NULL in queue.
3. While Queue is not empty
4. x = fetch first element from queue
5. If x is not NULL
6. x->rpeer <= top element of queue.
7. put left and right child of x in queue
8. else
9. if queue is not empty
10. put NULL in queue
11. end if
12. end while
13. return
#include <queue>
void print(tree* root)
{
queue<tree*> que;
if (!root)
return;
tree *tmp, *l, *r;
que.push(root);
que.push(NULL);
while( !que.empty() )
{
tmp = que.front();
que.pop();
if(tmp != NULL)
{
cout << tmp=>val; //print value
l = tmp->left;
r = tmp->right;
if(l) que.push(l);
if(r) que.push(r);
}
else
{
if (!que.empty())
que.push(NULL);
}
}
return;
}

I would use a collection, e.g. std::list, to store all elements of the currently printed level:
Collect pointers to all nodes in the current level in the container
Print the nodes listed in the container
Make a new container, add the subnodes of all nodes in the container
Overwrite the old container with the new container
repeat until container is empty

as an example of what you can do at an interview if you don't remember/don't know the "official" algorithm, my first idea was - traverse the tree in the regular pre-order dragging a level counter along, maintaining a vector of linked-lists of pointers to nodes per level, e.g.
levels[level].push_back(&node);
and in the end print the list of each level.

Related

Complexity of printing all root to leaf paths in binary tree

In https://www.techiedelight.com/print-all-paths-from-root-to-leaf-nodes-binary-tree/, the code for printing root to leaf for every leaf node is provided below.
They state the algorithm is O(n), but I think it should be O(n log n) where n is the number of nodes. A standard DFS is typically O(n + E), but printing the paths seems to add a log n. Suppose h is the height of the perfect binary tree. There are n/2 nodes on the last level, hence n/2 paths that we need to print. Each path has h + 1 (let's just say it's h for mathematical simplicity) nodes. So we need end up printing h * n/2 nodes when printing all the paths. We know h = log2(n). So h * n/2 = O(n log n)?
Is their answer wrong, or is there something wrong with my analysis here?
#include <iostream>
#include <vector>
using namespace std;
// Data structure to store a binary tree node
struct Node
{
int data;
Node *left, *right;
Node(int data)
{
this->data = data;
this->left = this->right = nullptr;
}
};
// Function to check if a given node is a leaf node or not
bool isLeaf(Node* node) {
return (node->left == nullptr && node->right == nullptr);
}
// Recursive function to find paths from the root node to every leaf node
void printRootToleafPaths(Node* node, vector<int> &path)
{
// base case
if (node == nullptr) {
return;
}
// include the current node to the path
path.push_back(node->data);
// if a leaf node is found, print the path
if (isLeaf(node))
{
for (int data: path) {
cout << data << " ";
}
cout << endl;
}
// recur for the left and right subtree
printRootToleafPaths(node->left, path);
printRootToleafPaths(node->right, path);
// backtrack: remove the current node after the left, and right subtree are done
path.pop_back();
}
// The main function to print paths from the root node to every leaf node
void printRootToleafPaths(Node* node)
{
// vector to store root-to-leaf path
vector<int> path;
printRootToleafPaths(node, path);
}
int main()
{
/* Construct the following tree
1
/ \
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
root->right->left->left = new Node(8);
root->right->right->right = new Node(9);
// print all root-to-leaf paths
printRootToleafPaths(root);
return 0;
}
The time comlexity of finding path is O(n) where it iterates through all nodes once.
The time comlexity of "print one path" is O(log n).
To print all paths (n/2 leaf), it takes O( n log n )
Then you need to compare node traverse cost and print path cost.
I believe in most of modern OS, print cost is much greater than node traverse cost.
So the actual time complexity is O(n log n) ( for print ).
I assume the website might ignore print cost so it claims time complexity is O(n).
The complexity is O(n log n) for a balanced binary tree, but for an arbitrary binary tree, the worst case is O(n2).
Consider a tree consisting of:
n/2 nodes in a linked list on their rightChild pointers; and
At the end of that, n/2 nodes arranged into a tree with n/4 leaves.
Since the n/4 leaves are all more than n/2 nodes deep, there are more than n2/8 total nodes in all the paths, and that is O(n2)
The algorithm traverses O(n) nodes. The total prints it does is O(n lg n) for a balanced tree or O(n^2) for an arbitrary tree.
It depends on what operations have cost.
For example, storing or incrementing an n bit number or pointer is often treated as an O(1) operation. In any physical computer, if you have 2^100 nodes you'll need lg(2^100) bit pointers (or node names) which will require more time to copy than 64 or 32 bit node names. Jn a certain sense, copying a pointer should take O(lg n) time!
But we don't care. We implicitly set the price of operations, and give O notation costs in terms of those operations.
Here, it is plausible they counted printing the entire path as an O(1) operation, and counted node traversals, to get an O(n) cost. Maybe they did it even notice, no more than you noticed the max node count implied by 32 or 64 bit pointers. They failed to tell you how they are pricing things.
The same thing happens in the specification of std library algorithms; it guarantees a max number of calls of a predicate.

Counting the number of nodes in a level of a binary search tree

Like the title says, I want to count the nodes in for any given level of the tree. I already know how to make member functions for counting all the nodes of the tree, just not sure how to approach a specific level. Here's what I've tried. Any help is appreciated.
First parameter is a point to a character array inputted by the user. root is a private variable representing the "oldest" node.
int TreeType::GetNodesAtLevel(ItemType* itemArray, int level)
{
TreeNode* p = root;
if (itemArray == NULL)
return;
if (level == 0)
{
cout << p->info << " ";
return;
}
else
{
GetNodesAtLevel(itemarray->left, level); //dereference in one and not the other was just testing
GetNodesAtLevel(*itemarray->right, level); //neither seems to work
}
}
The way to do it is by using a queue (employing level order traversal - BFS). Now follow this:
Take two variables, count_level and count_queue (keeping total nodes in a queue).
for a tree like this:
A
/ \
B C
/ \ \
K L D
/
E
initially count_level = 0 and count_queue = 0. Now:
Add a node to the queue(at this point A, increment count_queue to 1).
Now when you find count_level = 0 do this -> count_level = count_queue.
Add the kid nodes while dequeuing till the count_level becomes 0. So at this point the follow step 2 and that will give you the no of nodes at level beneath what just has been processed.

Range Queries on a path in a tree

I came across this question in a contest (which is now over) and I am not able to think of a time-efficient algorithm.
You are given a rooted Tree of N ( <=10^5) nodes . Initially all nodes have value 0.There would be M updates (<=10^5) to the tree which are of the form
Add x y – Add y to node x .
AddUp x y – Add y to x , parent of x , parent of parent of x uptill Root.
After that there will be Q queries ( <=10^5) queries where you will either be asked to give the value of a node or the sum of subtree rooted at that node.
What I did:-
First I tried the naive algorithm that would update each node according to the operation, but obviously it is time taking.
I also thought of using segment trees and Lazy propogation but cannot think of a proper way.
Any help is appreciated , Thanks!
First, construct a graph where the children point to their parents.
After that, parse all the updates and store in each node of your tree the sum of Add and AddUp separately.
Your node should have the following variables:
sum_add : the sum of all the Add of this node
sum_add_up : the sum of all the AddUp of this node
subtree_sum : the sum of the subtree. Initialize with 0 by now.
Now, transverse your graph using topological order, i.e., you will only process a node if all of its children were already processed, which takes O(N). Let me now define the process function.
process(V) {
V.sum_add_up = V.sum_add_up + sum(sum_add_up of all V.children)
V.subtree_sum = V.sum_add + V.sum_add_up + sum(subtree_sum of all V.children)
}
Now you can answer all the queries in O(1). The query for the value of a node V is V.sum_add + V.sum_add_up, and the query for the subtree of V is just V.subtree_sum.
This is a Fenwick Tree, for solve this kind of problems you must to execute a topological sort on tree and count the number of childrens for each node.
0
/ \
1 2
/ \
3 4
index: [0 1,2,3,4]
childrens: [4,2,0,0,0]
With topological you will obtain this vector 0 1 3 4 2 you need to reverse it:
fenwick Pos: [0,1,2,3,4]
vector values:[2,4,3,1,0]
pos: [5,3,0,2,1]
With fenwick tree you can execute 2 kinds of query, update query, range sum query
when you need to update a only a index call update(pos[index], y), then you must decrease all next values, update(pos[index]+1, -y)
When you need to update all parents call update(pos[index], y) and update(pos[index] + childrens[index] + 1, -y);
for know value of a position you need to call range sum query on pos[index]
I think this problem is just a direct application of a Binary Search Tree, which has an average-case cost (after n random operations) O(1.39log(n)) for both inserts and queries.
All you have to do is recursively add new nodes and update values and sum at the same time.
Implementation is also fairly simple (sorry for C#), for example for Add() (AddUp() is similar - increase value every time you go to left or right subtree):
public void Add(int key, int value)
{
Root = Add(Root, key, value);
}
private Node Add(Node node, int key, int value)
{
if (node == null)
{
node = new Node(key, value, value);
}
if (key < node.Key)
{
node.Left = Add(node.Left, key, value);
}
else if (key > node.Key)
{
node.Right = Add(node.Right, key, value);
}
else
{
node.Value = value;
}
node.Sum = Sum(node.Left) + Sum(node.Right) + node.Value;
return node;
}
For 100000 numbers on my machine this translates to these numbers:
Added(up) 100000 values in: 213 ms, 831985 ticks
Got 100000 values in: 86 ms, 337072 ticks
And for 1 million numbers:
Added(up) 1000000 values in: 3127 ms, 12211606 ticks
Got 1000000 values in: 1244 ms, 4857733 ticks
Is this time efficient enough? You can try complete code here.

Lock strategy of OpenMP programming in C++ for nested loops

Yesterday I tested my program of landscape evolution with a big data set(20 Million nodes), without a doubt the running speed was unacceptable. During debugging I noticed that it was a certain function which slowed the whole system down. So I'd like to add multithreading process to it.
However, the function itself is a nested loop with pointer iterators and I believe some of the data has to be locked during the process.
Basically what I was trying to do is to calculate the contributing area of each node. Contributing area, as suggested by its name, is a product (sum) of of all area from upstream node.
Here is the code of that two functions,
for( curnode = nodIter.FirstP(); nodIter.IsActive();
curnode = nodIter.NextP() ) //iterating thru a linked-list of pointers to active stream nodes (*IsActive* returns a bool value)
{
CalcDRArea( curnode, curnode->getVArea() ); //calls another function and pass a pointer to current node as well as a value of its VArea
}
void CalcDRArea( NodeClass *curnode, double addedArea )
{
// As long as the current node is neither a boundary nor non-valid, add
// _addedArea_ to its total drainage area and advance to the next node downstream
while( (curnode->ReachBoundary() == NonBoundary) &&
(curnode->valid()!=Nonvalid) )
{
curnode->AddDrArea( addedArea ); //*AddDrArea* is a simple inline function *`"drarea +=value"`*
curnode = curnode->getDownStreammNeighbor(); // *getDownstrmNbr()* reruns a pointer to the downstream node
}
}
Here is a simple illustration of nodes and their flowing direction
A B C D
\ | / |
E F G H
| |
I Q K L
| /
M N O P
//letters are stream nodes and slashes are their flowing directions
My plan is to use OpenMP to implement multithreading at the beginning of first function, the for loop. Ideally it will create several threads to calculate each node separately.
However, as shown in figure above, a sequent process can handle streams like
A-> F -> Q -> N
B-> F -> Q -> N
C-> F -> Q -> N
easily, but it will definitely cause problem in a multithreading conditions.
From what I've just read from OpenMP's document, flush and lock might be the right way to do this, but still I am quite clueless right now and there might still be other potential issues within this loops (like gcc ver. of OpenMP doesn't support "!=").
====Update ======
There are two kinds of areas: vArea, which is the area of each node; and drArea which is the sum of the area of current node and area from all its upstream nodes.
I was wondering if I can change the current function to this :
for( active node iterator)
{
if(currentNode.hasDownStreamNode)
{
downStreamNode.drArea += currentNode.vArea + currentNode.DrArea;
}
CurrentNode.drArea += currentNode.varea;
}
Before worrying about parallelism, you should first pick a better algorithm. Although in this case one actually goes with the other.
You want a dynamic programming solution in O(N) instead of your current O(n^2) approach. The intuition is simple, just call the following method on each of the leaf nodes in your tree:
def compute_value(node):
if node.DrArea != 0: return node.DrArea
total = node.vArea
for n in node.upstream_nodes():
total += compute_value(n)
node.DrArea = total
return node.DrArea
To see why this is more efficient, let's take a look at your example. At the moment you add the value of A to F, Q and N. Then you do the same for B and for C. So you have 12 add operations.
The recursive method on the other hand computes the value for A, B and C first, then we compute F from the already known values of A, B and C. Q gets computed from F and so on. So that's only 8 adds. Basically every node only adds its total value to all of its children instead of going through the whole subtree and adding only its own value.
For a simple sequential algorithm you can then go ahead and just implement this iteratively using a list of nodes whose predecessors have all been evaluated (so instead of starting from leaves start from the root nodes). The easiest parallel implementation here is to just use a concurrent queue and atomic add operations, although using one normal queue per processor and some work-stealing would probably be a very good idea in practice.

C++ - threaded tree, ordered traversal

I've just implemented a threaded tree in C++, and now I'm trying to cout all the elements in order.
The tree was a binary sorted tree (not balanced) before I've threaded it.
I've tried doing this:
E min = _min(root); //returns the minimum element of the tree
E max = _max(root); //returns the maximum element of the tree
while (min != max)
{
std::cout << min << ", ";
min = _successor(root, min);
}
std::cout << max << ", ";
std::cout << std::endl;
but since the tree is now threaded, my successor function always returns the minimum of the whole tree (basically, it goes once in the right subtree, and then goes in the left subtree as many times as possible, until it finds a leaf.) So when I try to call this function, it only cout 1's (because 1 is the minimum value of my tree).
Also, I've tried something else:
E min = _min(root); //returns min element of the tree
E max = _max(root); //returns max element of the tree
Node* tmp = _getNode(root, min); //returns the node of the specified element, therefore the minimum node of the tree
while(tmp->data < max)
{
std::cout << tmp->data << ", ";
tmp = _getNode(root, tmp->data)->rightChild; //gets the right child node of tmp
}
std::cout << tmp->data << ", ";
However, by doing this, there are values that are ignored. (See image below)
(Green links have been added after the threading of the tree.)
If you see, for example, the node #6 never gets visited from the very last algorithm, because it's not the right child of any node in the tree...
Here's the output of the previous function:
1, 2, 3, 5, 7, 8, 11, 71
Does anyone have an idea of how I could fix this, or any tips for my problem?
Thanks
EDIT: After all I just had to traverse the tree from the minimum to the maximum AND modify my _predecessor and _successor methods, so they wouldn't check in subtrees that are threaded. :)
Hope it helps future readers.
Try
Node* n = _min(root);
while (n->right) {
cout << n->val << ", ";
n = _successor(n);
}
cout << n->val << endl;
This is basically your first code (note that I assume that the tree is non-empty as do you). This also won't give you a trailing ','.
The important thing is to get your successor function correct. It should be like this
Node* _successor(Node* n) {
if (is_thread(o, RIGHT)) return o->right;
return _min(o->right);
}
And for completeness
Node* _min(Node* n) {
while (!is_thread(o, LEFT)) n = o->left;
return n;
}
For both of these all the green arrows are threads.
I've never seen threaded trees before, but I'll take a stab at this anyway. To build an inorder traversal, you could approach the root of the tree from two directions at once:
Start at the root.
Follow all left links until you find one that points to null. That element is the tree's minimum value.
Follow all right links until you reach the root. If you've built the tree correctly, this should traverse every element in increasing order.
Repeat steps 2 and 3 in the opposite direction (find the max element, walk backwards).
Join these two lists with the root in the middle.
That's probably not the fastest algorithm but I think it'll produce a correct answer. And you didn't have to use recursion, which I guess is the whole point for using a threaded tree.
After all I just had to traverse the tree from the minimum to the maximum
AND
modify my _predecessor and _successor methods, so they wouldn't check in subtrees that are threaded. :)
Hope it helps future readers.