I'm having a hard time printing the following tree:
----------t1:----------
tree:(((1),2,(3)),4,((5),6,(7,(8))))
----------t2:----------
tree:(((1),2,((3),4)),5,(6,(7,(8))))
----------t3:----------
tree:((1),2,(3,(4,(5,(6,(7,(8)))))))
----------t4:----------
tree:((((((((1),2),3),4),5),6),7),8)
where "father" have no parentheses and each "son" has a bracket depends on the depth,the picture are the trees with depth.
here is my code:
private String toString(String acc,int length){
if (left != null)
acc =left.toString(acc, length + 1)+")"+",";
// Adding two spaces 'length' times
for (int i = 0; i < length; i++) {
acc +="";
}
// adding the object data and new space
acc += this.data.toString();
if (right != null)
acc = "("+right.toString(acc, length + 1);
return acc;
}
public String toString() {
return "("+toString("", 0)+")";
}
which instead prints:
----------t1:----------
tree:(((((1),23),45),678)
----------t2:----------
tree:(((((1),23),4),5678)
----------t3:----------
tree:(((((((1),2345678)
----------t4:----------
tree:(1),2),3),4),5),6),7),8)
in the added picture, the tree is demonstrated with depth
Actually, every node has an opening and closing parenthesis. As Stefan commented, you don't need the depth. Here's the code:
public String toString() {
String out = "(";
if (this.left != null) {
out += left.toString() + ",";
}
out += this.data;
if (this.right != null) {
out += "," + right.toString();
}
return out + ")";
}
My method is suppose to return a random node from a BST, however it is not working correctly and I am unsure of why. The method is suppose to traverse the tree using preorder traversal while incrementing the counter. Once the counter is equal to the randomly generated number, it is suppose to return the node.
// get random node
public Node getRandomNode(Node root) {
// get random value between 0 to size of BST
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
Node temp = root;
System.out.println("random number is: " + ranNum);
root = getRandomNode(ranNum, temp);
return root;
}
int count = 0;
public Node getRandomNode(int ranNum, Node temp) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (temp != null && count != ranNum) {
count++;
temp = getRandomNode(ranNum, temp.left);
System.out.println(temp.data);
temp = getRandomNode(ranNum, temp.right);
}
// if count is equal to the randomly generated number
return temp;
}
EDIT:
Using BFS
public Node getRandomNode(int ranNum, int count, Node temp) {
if(temp == null)
return null;
Queue<Node> q = new LinkedList<Node>();
q.add(temp);
count++;
while(!q.isEmpty() && count != ranNum) {
Node n = q.remove();
System.out.println(" " + n.data);
if(count == ranNum) {
System.out.println("final node: " + n.data);
return n;
}
if(n.left != null) {
q.add(n.left);
count++;
}
if(n.right != null) {
q.add(n.right);
count++;
}
}
return temp;
}
Your problem is in your recursive calls. Assume the random number is 1, you would expect the returned result to be the first node reached from the left subtree. Your code will say temp = getRandomNode(ranNum, temp.left);, and at this point the temp variable holds the correct answer, then you say temp = getRandomNode(ranNum, temp.right);, and at this point your temp variable holds an incorrect answer.
EDIT:
I decided to try to quickly fix your BFS implementation (quick = untested). Note that I'm trying to keep my code as close to yours as I can, so I'm avoiding making any changes to your algorithm.
public Node getRandomNode(Node temp, int ranNum) {
if(temp == null)
return null;
Queue<Node> q = new LinkedList<Node>();
q.add(temp);
int count = 0;
while(!q.isEmpty() && count <= ranNum) {
Node current = q.remove();
System.out.println(" " + result.data);
if(count == ranNum) {
System.out.println("final node: " + n.data);
return n;
}
if(n.left != null) {
q.add(n.left);
}
if(n.right != null) {
q.add(n.right);
}
count++
}
return null;
}
EDIT2:
Decided to fix your other version as well (still trying to stick very close to your original design).
// get random node
public Node getRandomNode(Node root) {
// get random value between 0 to size of BST
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
System.out.println("random number is: " + ranNum);
return getRandomNode(ranNum, root);
}
int count = 0;
public Node getRandomNode(int ranNum, Node node) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (node == null || count == ranNum) {
return node;
}
count++;
temp = getRandomNode(ranNum, temp.left);
if (temp != null) {
return temp;
}
return getRandomNode(ranNum, temp.right);
}
Your implementation is not totally random because you are retrieving the random node based on a count (randomly picked) but not randomly traversed!
the tree should return null if and only if the tree is empty.
because you have generated the random based on the size of the tree.
the Tree has two paths either right or left ...going either way should be random too ! And should be thru one of them per method call(unless the the branch has been exhausted ).
I changed the count variable from field to a method parameter 'cause it seems to be a temp and has nothing to do with class
thus you don't have to reset the count each use of the class as well it is a good practice.
* another concern that you check for null what if the one of the side has a less
number than the other that would make the the function exits because the node is
null if this occurred on the left side traverse it the right would replace the temp but what if it happened on the other way it may return null !
by the way consider this as pseudo code I have never tested it :)
public Node getRandomNode(Node root) {
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
Node temp = root;
System.out.println("random number is: " + ranNum);
root = getRandomNode(ranNum, temp,0);
return root;
}
public Node getRandomNode(int ranNum, Node temp, int count ) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (temp != null && count != ranNum) {
count++;
Random pathRan = new Random();
int pathNo= pathRan.nextInt(2);
Node temp2 = null;
if(pathNo == 0){//if 0 go to left
temp2 = getRandomNode(ranNum, temp.left,count);
if(temp2 == null){//this means that this path has nodes less than count ,so try the right.
temp2 = getRandomNode(ranNum, temp.right,count);
}
}else{//go to right
temp2 = getRandomNode(ranNum, temp.right,count);
if(temp2 == null){//this means that this path has nodes less than count ,so try the left.
temp2 = getRandomNode(ranNum, temp.left,count);
}
}
return temp2;
}
// if count is equal to the randomly generated number
return temp;
}
So I want my printout of my binary tree to read like [A B C D E F] but I keep ending up with an extra space and I can't use subString to remove it. What is the best way to approach this?
public String toStringInOrder() {
output = "";
output += printInOrder(root);
if(output.length() < 1) {
return "[]";
} else {
return "[" + output.substring(0, output.length() - 1) + "]";
}
}
private String printInOrder(Node current) {
if(current != null) {
printInOrder(current.left);
output += current.value + " ";
printInOrder(current.right);
}
return output;
}
If your only concern is removing the extra space at the end you could replace:
return "[" + output.substring(0, output.length() - 1) + "]";
with:
return "[" + output.Trim() + "]";
Another approach I might take is filling a List with the ordered values, and then you can have a greater control of how you format the ordered values as a string.
If you can't use substring or similars, do a "look for maximum node" search (cheap log(n) operation), save that node and add an if statement on your output additions that checks if the node whose info has to be added isn't the last one. In that case, add the value without the space.
Node last = max(root);
private Node max(Node x){
if (x.right == null)
return x;
return max(x.right);
}
private String printInOrder(Node current) {
if(current != null) {
printInOrder(current.left);
if(!current.equals(last))
output += current.value + " ";
else
output += current.value;
printInOrder(current.right);
}
return output;
}
I discovered the answer I needed after some diagramming and trial and error.
private String printPreOrder(Node current) {
if (current != null) {
output += current.value;
if (current.left != null) output += " ";
printPreOrder(current.left);
if (current.right != null) output += " ";
printPreOrder(current.right);
}
return output;
}
Some changes to the inOrder and postOrder garners similar results. Thanks to all for the help!
Problem Statement
You are given a pointer to the root of a binary tree. Print the top view of the binary tree.
You only have to complete the function.
My Code:
void top_view(Node root)
{
Node r = root;
if(r.left!=null){
top_view(r.left);
System.out.print(r.data + " ");
}
if(r.right!=null){
System.out.print(r.data + " ");
top_view(r.right);
}
}
The two if statements are executed every time the function is called, but I need only one of them to execute. I tried switch but its giving constant expression error. I have already found a different solution for this problem.
So I only want to know if we can make only one if execute at a time i.e, is there a way to fix my code without changing the approach?
Problem link: https://www.hackerrank.com/challenges/tree-top-view
Your approach will work not because, when you call left or right subtree you will just stick to it. The problem with this approach is you are just driven by which side of the tree is called first.
May be you can solve it by using stack and queue as somebody else said but i feel that the following is a simpler and more intuitive approach:
(SEE THE CODE AT THE END, IT'S VERY SIMPLE)
The approach to solve this is by maintaining horizontal distance from root and you print the first node for each different horizontal distance.
What is horizontal distance?
I am just taking the image you have added.
Horizontal distance for a particular node is defined as the number of from root horizontally. If you see no.of edges that will become vertical distance.
To make things easier for all the nodes on left side of root start with negative horizontal distance and right side positive distance.
How do you calculate horizontal distance?
If you are going right add 1, if you are going left add -1.
so
horizontal distance of 3 = 0
horizontal distance of 5 = -1
horizontal distance of 1 = -2
horizontal distance of 9 = -1
horizontal distance of 4 = 0
horizontal distance of 2 = 1
horizontal distance of 6 = 0
horizontal distance of 7 = 2
horizontal distance of 8 = 1
Nodes 3,4,6 have same horizontal distance of 0 what does the mean?
That means when you see from top all these nodes are in a line vertically one above it.
If they are in a line vertically which one do you see?
The one which is can be reached first from root.
How do you find which one can be reached first?
as usual BFS
How this prints solution for your example?
There are five different horizontal distance value {-1,-2,0,1,2}
hor dist Nodes
0 - {3,6,8} // 3 comes first in BFS so print 3
-1 - {5,9} // 5 comes first in BFS so print 5
-2 - {1} // just print 1
1 - {2} // just print 2
2 - {7} // just print 7
So it will print {3,5,1,2,7}
HashSet<Integer> set = new HashSet<>();
Queue<QueueItem> queue = new LinkedList<>();
queue.add(new QueueItem(root, 0)); // Horizontal distance of root is 0
while (!queue.isEmpty())
{
QueueItem temp = queue.poll();
int hd = temp.hd;
TreeNode n = temp.node;
// If this is the first node at its horizontal distance,
// then this node is in top view
if (!set.contains(hd))
{
set.add(hd);
System.out.print(n.key + " ");
}
if (n.left != null)
queue.add(new QueueItem(n.left, hd-1));
if (n.right != null)
queue.add(new QueueItem(n.right, hd+1));
}
The solution is pretty easy if you print the left side by recursion and the right side using a simple while loop..
void for_left(node *root)
{
if(!root->left)
{
cout<<root->data<<" ";
return;
}
for_left(root->left);
cout<<root->data<<" ";
return;
}
void top_view(node * root)
{
for_left(root->left);
cout<<root->data<<" ";
while(root->right)
{
cout<<(root->right)->data<<" ";
root=root->right;
}
}
This problem can be very easily solved by using:
Stack: To print the root and the left subtree.
Queue: To print the right subtree.
Your function should be like this:
void topview(Node root)
{
if(root==null)
return;
Stack<Integer> s=new Stack<Integer>();
s.push(root.data);
Node root2=root;
while(root.left!=null)
{
s.push(root.left.data);
root=root.left;
}
while(s.size()!=0)
System.out.print(s.pop()+" ");
Queue<Integer> q=new LinkedList<Integer>();
q.add(root2.right.data);
root2=root2.right;
while(root2.right!=null)
{
q.add(root2.right.data);
root2=root2.right;
}
while(q.size()!=0)
System.out.print(q.poll()+" ");
}
This one actually works. Doesn't need a queue, but uses a stack in order to backtrack from the left side, since we don't have reference to the parent.
void top_view(Node root)
{
Stack<Node> p = new Stack<Node>();
Node current = root;
while (current != null)
{
p.push(current);
current = current.left;
}
while (p.peek() != root)
{
System.out.print(p.pop().data + " ");
}
current = root;
while (current != null)
{
System.out.print(current.data + " ");
current = current.right;
}
}
The solution can be found here - Git hub URL
Note that whatever the hackerrank question is with respect to balanced tree, if the tree is in the imbalanced state like below
1
/ \
2 3
\
4
\
5
\
6
For these kind of trees some complicated logic is required which is defined in geeksforgeeks here - GeeksforGeeks
My Java implementation is attached. The left side of the tree is more interesting if solved recursively, but reversing the string(my way below) was easier and only required the use of one method.
public void top_view(Node root){
String output = "";
Node left = root.left;
Node right = root.right;
String leftOutput = "";
while(left != null){
leftOutput += left.data + " ";
left = left.left;
}
String left = "";
for(int i = leftOutput.length - 1; i >= 0; i--){
left += leftOutput.substring(i, i+1);
}
output += left;
output += " " + root.data + " ";
while(right != null){
output += right.data + " ";
right = right.right;
}
output = output.substring(1, output.length());
System.out.println(output);
}
void top_view(Node root)
{
if(root.left!=null) top_view(root.left);
if(root.left!=null || root.right!=null)
System.out.print(root.data + " ");
if(root.right!=null) top_view(root.right);
}
A simpler approach in C++
`// printing top view of the tree
void left_array(node *p)
{
if(p==NULL)
return;
else
{
left_array(p->left);
cout<<p->data<<" ";
}
}
void right_array(node *p)
{
if(p==NULL)
return;
else
{
cout<<p->data<<" ";
right_array(p->right);
}
}
void top_view(node * root)
{ int i=0;
node *t1=root;
node *t2=root;
left_array(t2);
right_array(t1->right);
}`
A very simple recursive solution which takes care of long branches of the child node. This is solved using horizontal distance concept.
public void printTopView(BNode root) {
Map<Integer, Integer> data = new TreeMap<Integer, Integer>();
printTopViewRecursive(data, root, 0);
for(int key : data.keySet()) {
System.out.print(data.get(key) +" ");
}
}
private void printTopViewRecursive(Map<Integer, Integer> hDMap, BNode root, int hD) {
if(root == null)
return;
if(!hDMap.containsKey(hD)) {
hDMap.put(hD, root.data);
}
printTopViewRecursive(hDMap, root.left,hD - 1);
printTopViewRecursive(hDMap, root.right, hD + 1);
}
in java recursivish solution. converted from c++ code
void top_view(Node root)
{
left_array(root);
right_array(root.right);
}
void left_array(Node p)
{
if(p==null)
return;
else
{
left_array(p.left);
System.out.printf("%d ",p.data);
}
}
void right_array(Node p)
{
if(p==null)
return;
else
{
System.out.printf("%d ",p.data);
right_array(p.right);
}
}
void top_view(Node root)
{
Node left = root;
Node right = root;
print_left(root.left);
System.out.print(root.data + " ");
print_right(root.right) ;
}
void print_left(Node start)
{
if(start != null)
{
print_left(start.left);
System.out.print(start.data + " ");
}
}
void print_right(Node start)
{
if(start != null)
{
System.out.print(start.data + " ");
print_right(start.right);
}
}
One simple recursive way to do it:
void top_view(Node root)
{
print_top_view(root.left, "left");
System.out.print(root.data + " ");
print_top_view(root.right, "right");
}
void print_top_view(Node root, String side) {
if(side.equals("left")) {
if(root.left != null) {
print_top_view(root.left, "left");
}
System.out.print(root.data + " ");
} else if(side.equals("right")) {
System.out.print(root.data + " ");
if(root.right != null) {
print_top_view(root.right, "right");
}
}
}
if(root){
if(root->left !=NULL || root->right !=NULL){
if(root->left)
top_view(root->left);
cout<<root->data<<" ";
if(root->right)
top_view(root->right);
}}
This is the code for top-view of a binary tree in c++..
void topview(node* root,queue &Q)
{
if(!root)
return;
map<int,int> TV;
Q.push(root);
TV[root->data]=0;
map<int,int>:: iterator it;
int min=INT_MAX,max=INT_MIN;
while(!Q.empty())
{
node* temp =Q.front();
Q.pop();
int l=0;
for(it=TV.begin();it!=TV.end();it++)
{
if(it->first==temp->data)
{
l=it->second;
break;
}
}
if(l<min)
{min=l;}
if(l>max)
max=l;
if(temp->left)
{
Q.push(temp->left);
TV[temp->left->data] = l-1;
}
if(temp->right)
{
Q.push(temp->right);
TV[temp->right->data] = l+1;
}
}
cout<<max<<min<<endl;
for(int i =min;i<=max;i++)
{
for(it=TV.begin();it!=TV.end();it++)
{
if(it->second==i)
{
cout<<it->first;
break;
}
}
}
}
void topview_aux(node* root)
{
queue<node*> Q;
topview(root,Q);
}
A quite similar approach to the one #Karthik mentioned but with keeping the order, is to postpone the printing to the end and keep top view nodes ordered in double ended queue.
We guarantee the order using BFS
Each round we check if the current node's horizontal distance is larger than the maximum distance reached in the previous rounds (negative distance for left nodes).
New top view nodes with -ve distance (left position) added to the left end of the deque , while right nodes with +ve distance added to the right end.
Sample solution in Java
import java.util.*;
class Node {
int data;
Node left;
Node right;
public Node(int data) {
this.data = data;
}
}
enum Position {
ROOT,
RIGHT,
LEFT
}
class NodePositionDetails {
Node node;
// Node position in the tree
Position pos;
// horizontal distance from the root (-ve for left nodes)
int hd;
public NodePositionDetails(Node node, Position pos, int hd) {
this.node = node;
this.pos = pos;
this.hd = hd;
}
}
public class TreeTopView {
public void topView(Node root) {
// max horizontal distance reached in the right direction uptill the current round
int reachedRightHD = 0;
// max horizontal distance reached in the left direction uptill the current round
int reachedLeftHD = 0;
if (root == null)
return;
// queue for saving nodes for BFS
Queue < NodePositionDetails > nodes = new LinkedList < > ();
// Double ended queue to save the top view nodes in order
Deque < Integer > topViewElements = new ArrayDeque < Integer > ();
// adding root node to BFS queue
NodePositionDetails rootNode = new NodePositionDetails(root, Position.ROOT, 0);
nodes.add(rootNode);
while (!nodes.isEmpty()) {
NodePositionDetails node = nodes.remove();
// in the first round, Root node is added, later rounds left and right nodes handled in order depending on BFS. if the current horizontal distance is larger than the last largest horizontal distance (saved in reachedLeftHD and reachedRightHD)
if (node.pos.equals(Position.LEFT) && node.hd == reachedLeftHD - 1) {
topViewElements.addFirst(node.node.data);
reachedLeftHD -= 1;
} else if (node.pos.equals(Position.RIGHT) && node.hd == reachedRightHD + 1) {
topViewElements.addLast(node.node.data);
reachedRightHD += 1;
} else if (node.pos.equals(Position.ROOT)) { // reachedLeftHD == 0 && reachedRightHD ==0
topViewElements.addFirst(node.node.data);
}
// Normal BFS, adding left and right nodes to the queue
if (node.node.left != null) {
nodes.add(new NodePositionDetails(node.node.left, Position.LEFT, node.hd - 1));
}
if (node.node.right != null) {
nodes.add(new NodePositionDetails(node.node.right, Position.RIGHT, node.hd + 1));
}
}
// print top elements view
for (Integer x: topViewElements) {
System.out.print(x + " ");
}
}
}
And for testing:
public static void main(String[] args) throws java.lang.Exception {
/**
Test Case 1 & 2
1
/ \
2 3
/ \
7 4
/ \
8 5
\
6
Test Case 3: add long left branch under 3 (branch : left to the 3 3-> 8 -> 9 -> 10 -> 11
**/
Node root = new Node(1); //hd = 0
// test Case 1 -- output: 2 1 3 6
root.left = new Node(2); // hd = -1
root.right = new Node(3); // hd = +1
root.left.right = new Node(4); // hd = 0
root.left.right.right = new Node(5); // hd = +1
root.left.right.right.right = new Node(6); // hd = +2
// test case 2 -- output: 8 7 2 1 3 6
root.left.left = new Node(7); // hd = -2
root.left.left.left = new Node(8); // hd = -3
// test case 3 -- output: 11 7 2 1 3 6
root.left.left.left = null;
root.right.left = new Node(8); //hd = 0
root.right.left.left = new Node(9); // hd = -1
root.right.left.left.left = new Node(10); // hd = -2
root.right.left.left.left.left = new Node(11); //hd = -3
new TreeTopView().topView(root);
}
Simplest Recursive Solution
void top_view(Node root)
{
// For left side of the tree
top_view_left(root);
// For Right side of the tree
top_view_right(root.right);
}
void top_view_left(Node root){
if(root != null)
{
// Postorder
top_view_left(root.left);
System.out.print(root.data + " ");
}
}
void top_view_right(Node root){
if(root != null)
{
// Preorder
System.out.print(root.data + " ");
top_view_right(root.right);
}
}
This:
import queue
class NodeWrap:
def __init__(self, node, hd):
self.node = node
#horizontal distance
self.hd = hd
def topView(root):
d = {}
q = queue.Queue()
q.put(NodeWrap(root, 0))
while not q.empty():
node_wrap = q.get()
node = node_wrap.node
current_hd = node_wrap.hd
if d.get(current_hd) is None:
d[current_hd] = node
print(node.info, end=" ")
if node.left is not None:
q.put(NodeWrap(node.left, current_hd - 1))
if node.right is not None:
q.put(NodeWrap(node.right, current_hd + 1))
has to be working solution on Python but for some reasons it fails on 6 test cases from 7 on hackerrank.com. Can somebody explain me why it is happening?
Those people who just run "left" and "right" functions don't understand the task.
def printTopView(root):
lst=[]
current1=root.left
while current1!=None:
lst.append(current1.key)
current1=current1.left
lst.reverse()
current2=root
while current2!=None:
lst.append(current2.key)
current2=current2.right
print(*lst)
Some of the answers above do not work. I tried commenting on them, but, apparently, I don't have the right score, since I've never tried to comment here before.
The problem is that you need to do a breadth first search of the tree to ensure the correct order of the nodes. To exclude "obscured" nodes, another website suggested ranking each node. The root is 0. All branches to the left of a node, have the parent rank, -1. All branches to the right have the parent rank +1. Any nodes with a duplicate rank of its ancestor are excluded.
Then print out the selected nodes in rank order. This will work in all cases.
Python Solution
Solve using Breadth First Traversal
def topView(root):
q = deque()
#Adding root node to the deque along with its Horizontal Distance from root.
q.append([root,0])
#Dictionary to store the {Horizontal Distance: First Node that has this distance}
s = {}
#Breadth First Traversal - [To keep track of the first Node that is visited.]
while q:
temp = q.popleft()
#Horizontal Distance from Root
d = temp[1]
#Adding the Left Child to the Queue (if Exists)
if temp[0].left is not None:
q.append([temp[0].left, d-1])
#Adding the Right Child to the Queue (if Exists)
if temp[0].right is not None:
q.append([temp[0].right, d+1])
#Adding the Horizontal Distance and the First Node that has this distance to Dictionary.
if d not in s:
s[d] = temp[0].info
#Printing out the Top View of Tree based on the values in the Dictionary - From least to Highest Horizontal Distance from Root Node.
for i in sorted(s):
print(s[i], end=" ")