Trying to print top view of a tree using two if statements - java

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=" ")

Related

Why do we need a temporary node while inserting values in a node in Linked list?

I was creating a binary tree using linked list in java, which inserts the value according to the height of the tree i.e if the height is even or odd. I wrote a code which initially had no temporary node for insertion of values to the root node and further left or right subtree nodes. But when I displayed this tree, output had no root node as if it was overwritten.
Below is the code of my initial program. Concentrate on public void insert_node() function.
import java.util.Scanner;
public class binary_tree {
private TreeNode root;
private int height = 0;
public static class TreeNode {
private int data;
private TreeNode left;
private TreeNode right;
public TreeNode(int user_input) {
this.data = user_input;
}
}
public void insertNode(TreeNode newnode) { // HERE....I have used only root.
if (root == null) {
root = newnode;
height += 1;
return;
}
if (height % 2 != 0) {
System.out.println(height);
while (root.left != null) {
root = root.left;
}
root.left = newnode;
height += 1;
return;
}
while (root.right != null) {
root = root.right;
}
root.right = newnode;
height += 1;
}
public void display(TreeNode rootnode) {
TreeNode temp = rootnode;
if (temp == null)
System.out.println("Tree Empty !!!");
else {
System.out.println("press 1 for LEFT SUBTREE \npress 2 for RIGHT SUBTREE.");
Scanner sc = new Scanner(System.in);
int ch = sc.nextInt();
while (temp != null) {
System.out.println(temp.data + " $");
if (ch == 1)
temp = temp.left;
else
temp = temp.right;
}
}
System.out.println("Height of the tree = " + height);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
binary_tree bt = new binary_tree();
TreeNode newNode = new TreeNode(50);
bt.insertNode(newNode);
TreeNode newNode2 = new TreeNode(10);
bt.insertNode(newNode2);
TreeNode newNode3 = new TreeNode(100);
bt.insertNode(newNode3);
TreeNode newNode4 = new TreeNode(5);
bt.insertNode(newNode4);
TreeNode newNode5 = new TreeNode(1000);
bt.insertNode(newNode5);
bt.display(bt.root);
}
}
Output
press 1 for LEFT SUBTREE
press 2 for RIGHT SUBTREE.
3
10 $
1000 $
Height of the tree = 5
You can see in the above code, that the 50 $ is missing which was supposed to be the root node.
Now, if I use a temporary node which in my case is current_node then this root node sustains somehow. See in the code below.
import java.util.Scanner;
public class binary_tree {
private TreeNode root;
private int height = 0;
public static class TreeNode {
private int data;
private TreeNode left;
private TreeNode right;
public TreeNode(int user_input) {
this.data = user_input;
}
}
public void insertNode(TreeNode newnode) {
TreeNode current_node = root; //THIS IS THE TEMPORARY NODE
if (current_node == null) {
root = newnode;
height += 1;
return;
}
if (height % 2 != 0) {
System.out.println(height);
while (current_node.left != null) {
current_node = current_node.left;
}
current_node.left = newnode;
height += 1;
return;
}
while (current_node.right != null) {
current_node = current_node.right;
}
current_node.right = newnode;
height += 1;
}
public void display(TreeNode rootnode) {
TreeNode temp = rootnode;
if (temp == null)
System.out.println("Tree Empty !!!");
else {
System.out.println("press 1 for LEFT SUBTREE \npress 2 for RIGHT SUBTREE.");
Scanner sc = new Scanner(System.in);
int ch = sc.nextInt();
while (temp != null) {
System.out.println(temp.data + " $");
if (ch == 1)
temp = temp.left;
else
temp = temp.right;
}
}
System.out.println("Height of the tree = " + height);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
binary_tree bt = new binary_tree();
TreeNode newNode = new TreeNode(50);
bt.insertNode(newNode);
TreeNode newNode2 = new TreeNode(10);
bt.insertNode(newNode2);
TreeNode newNode3 = new TreeNode(100);
bt.insertNode(newNode3);
TreeNode newNode4 = new TreeNode(5);
bt.insertNode(newNode4);
TreeNode newNode5 = new TreeNode(1000);
bt.insertNode(newNode5);
bt.display(bt.root);
}
}
Output
press 1 for LEFT SUBTREE
press 2 for RIGHT SUBTREE.
3
50 $
100 $
1000 $
Height of the tree = 5
So anyone who can tell me what's happening here? What difference does that current_node is making?
Why do we need a temporary node while inserting values in a node in Linked list?
Because you are traversing to the leaves of the tree here:
while (current_node.left != null) {
current_node = current_node.left;
}
current_node.left = newnode;
height += 1;
In these lines of code, you are trying to find the leftmost leaf so as to insert newnode, right? You want to use a variable to keep track of which node you are currently on, and "go left" by doing someVariable = someVariable.left;.
You could use root to keep track of where you are at, but root already has a purpose - to record the root of the tree! If you did root = root.left;, you are making the left node of the original root be the new root! Say your tree was:
50
/ \
10 100
Doing root = root.left deletes most of it:
10
This is problematic because this means your tree essentially "forgets" about a part of the tree. Technically, The 50 and 100 nodes still exists and 50 is still connected to 10, but your binary_tree object doesn't have access to it anymore. The only point of access it has is root, which you have now set to the node 10.
What actually happens in your program is: it correctly inserts 50, 10, and 100, then when adding 5, tries to traverse down the left subtree. This makes the root "10", and adding 5 becomes:
10
/
5
It then adds 1000 correctly:
10
/ \
5 1000
Hence it prints 10 and 1000.
Using a brand new variable solves this problem, because the brand new variable has nothing to do with root.

[JAVA} A-Star code isn't finding optimal Path

I'm trying to code A* search algorithm but I can't seem to get it to work. I'm copying the pseudocode from wikipedia. My code seems to just search every possible node. Here's my showPath() function:
public void showPath() {
Nodes current = end;
while(current.cameFrom!=null) {
current.isPath = true;
current = current.cameFrom;
}
}
The start node will have a cameFrom of null since that's it's default value.
public void A_Star() {
PriorityQueue<Nodes> closedSet = new PriorityQueue<Nodes>();
PriorityQueue<Nodes> openSet = new PriorityQueue<Nodes>();
closedSet.clear();
openSet.clear();
start.gScore = 0;
openSet.add(start);
start.fScore = getDist(start,end);
while(!(openSet.size() ==0)) {
Nodes curr = openSet.poll();
if(curr.x == end.x && curr.y == end.y) {
showPath();
}
closedSet.add(curr);
for(int i=0;i<curr.getNeighbourCount();i++) {
Nodes neighbour = curr.getNeighbour(i);
if(closedSet.contains(neighbour)) {
continue;
}
//isPassable is a boolean that is false if the Nodes is an obstacle
if(!openSet.contains(neighbour) && neighbour.isPassable) {
openSet.add(neighbour);
}
//It's a grid so every point is a distance of 1 from it's neighbours
else if((curr.gScore+1)>= neighbour.gScore){
continue;
}
neighbour.cameFrom = curr;
neighbour.gScore = curr.gScore+1;
neighbour.fScore = neighbour.gScore + getDist(neighbour,end);
}
}
}
EDIT: My getDist function
public int getDist(Nodes node1, Nodes node2) {
return ( Math.abs(node1.x - node2.x) + Math.abs(node1.y - node2.y));
}
If you look at this picure, you have to notice that, with Manhatten distance, all of the paths from start to the goal has equal distances. This will cause that, you will visit all.
Change your distance to Euclidean Distance.

A* algorithm infinite while-loop

I've been attempting to follow some pseudocode, namely
https://www.geeksforgeeks.org/a-search-algorithm/ &
http://mat.uab.cat/~alseda/MasterOpt/AStar-Algorithm.pdf ,
to create an A star pathfinding algorithm for a four-directional tile/cell-based map with obstacles. I understand the concept, and I could definitely explain how it should work in words/images, but putting it into code is proving challenging. For a few days now whenever I've run my program it crashes and I have to manually stop the application. I believe this is due to an infinite while-loop. This confuses me because the program should exit the while-loop once its found the end destination, but obviously that isn't working. This is the code which I think should make it exit the while-loop once the destination is found:
if (n.getX() == end.getX() && n.getY() == end.getY()) {
currentNode = n;
break;
}
I hope this isn't too much code to put in this post, but this is the meat of my algorithm with comments on what I think each piece is doing:
public void attempt2() {
double leastF = Integer.MAX_VALUE;
// Initializes the starting Node and, in the beginning, currentNode is the same
// as the starting node
Node start = new Node(r.getCell());
Node currentNode = start;
start.setParent(start);
closed.add(start);
open.add(start);
start.setEnd(destinationCP);
start.calculateH();
start.isCalculatedH();
while (open.size() > 0) {
// Finds the node with the least F score on Open
for (Node n : open) {
// Calculates the H-score if it hasn't been already
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
// Calculates the g-score, with 1 being the value/distance of a cell
n.setAdditiveDistanceG(n.getAdditiveDistanceG() + 1);
// Calculates the F-score
n.calculateF();
// Actually finds the least F score in the open list and sets currentNode to the
// node with the least F
if (n.getTotalCostF() < leastF) {
leastF = n.getTotalCostF();
currentNode = n;
}
}
//
// Creates easy-access variables for the x and y values of the node on open with
// the least F score
int thisX = currentNode.getX();
int thisY = currentNode.getY();
// if this cell (cell in open w least F) is the end destination cell, stop the calculations
if (thisX == end.getX() && thisY == end.getY()) {
break;
}
//
// Generate 1-4 successors if Robot can pass into the cell
if (World.getCell(thisX + 1, thisY).canEnter(r)) {
successors.add(new Node(World.getCell(thisX + 1, thisY)));
}
if (World.getCell(thisX, thisY + 1).canEnter(r)) {
successors.add(new Node(World.getCell(thisX, thisY + 1)));
}
if (World.getCell(thisX - 1, thisY).canEnter(r)) {
successors.add(new Node(World.getCell(thisX - 1, thisY)));
}
if (World.getCell(thisX, thisY - 1).canEnter(r)) {
successors.add(new Node(World.getCell(thisX, thisY - 1)));
}
//
/*
* Loops through each of the 1-4 neighbors to currentNode (I need to add in to
* erase & add to open/closed every one in here so its empty before new ones are
* generated
*/
for (Node n : successors) {
double successorCurrentCost = 0;
// if this successor is already in the closed list, skip doing all the code for
// this node and add this successor's parent (currentNode) to the closed list
if (isInClosed(n)) {
continue;
}
// if this is the goal/end node, exit the 'successors' for-loop. the step that
// follows this (exiting the loop) is that this particular node/successor is
// added to the closed list
if (n.getX() == end.getX() && n.getY() == end.getY()) {
currentNode = n;
break;
}
//
// Calculates the F cost for each successor to currentNode
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
n.setAdditiveDistanceG(n.getAdditiveDistanceG() + currentNode.getAdditiveDistanceG());
n.calculateF();
successorCurrentCost = n.getTotalCostF();
//
if (!isInOpen(n) && n.getAdditiveDistanceG() > successorCurrentCost
|| n.getAdditiveDistanceG() > successorCurrentCost && !isInClosed(n)) {
open.add(n);
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
} else if (isInClosed(n) && n.getAdditiveDistanceG() <= successorCurrentCost) {
successorCurrentCost = n.getAdditiveDistanceG();
n.setParent(currentNode);
} else {
successorCurrentCost = n.getAdditiveDistanceG();
n.setParent(currentNode);
}
if (isInClosed(n)) {
closed.remove(n);
open.add(n);
}
}
closed.add(currentNode);
if (thisX == end.getX() && thisY == end.getY()) {
break;
}
}
if (currentNode.getMyCell() != this.destinationCP) {
System.out.println("ERROR: open list is empty");
return;
} else {
createPath();
}
}
I am aware that there are a few things that should be changed in this code, however I am most concerned about the while loop never being terminated. Any other comments about my code are appreciated but definitely not necessary.

Print a binary search tree as a single string

There's a practice problem that I've been working on that's been confusing me.
Define a function treeLevelOrder which satisfies the following claim:
If Q is a binary search tree of integers, then treeLevelOrder(Q) is the String representation of the contents of Q according to their level in the tree.
We get this tree as an example
9
/ \
5 16
/ \ / \
1 7 12 19
The value of the expression treeLevelOrder(Q) in this case would be
"[9,5,16,1,7,12,19]".
I've seen similar problems, but they don't follow the same format that I'm looking for, wanting to print by level order or as ordered tuples. Here's some sample code I've been working on:
private String treeLevelOrder(Node Q)
{
if (Q.left == null && Q.right == null)
return "[" + Q.datum + "]";
else if (Q.left == null && Q.right != null)
return "[" + Q.datum + ", "+Q.right.datum+"]" + treeLevelOrder(Q.right);
else if (Q.left !=null && Q.right == null)
return"[" + Q.datum + ", "+Q.left.datum+", *]"+ treeLevelOrder(T.left);
else
return "[" + Q.datum + ", "+Q.left.datum+", "+Q.right.datum+"]" +
treeLevelOrder(Q.left) + treeLevelOrder(Q.right);
}
Any assistance would be helpful.
EDIT: Okay, so I've been experimenting with the level order example at Geeks for Geeks, thank you curlyBraces, that would be closer to what I'm looking for, though I can't figure out to make it return a string. Here's the code they use:
/* function to print level order traversal of tree*/
void printLevelOrder()
{
int h = height(root);
int i;
for (i=1; i<=h; i++)
printGivenLevel(root, i);
}
/* Compute the "height" of a tree -- the number of
nodes along the longest path from the root node
down to the farthest leaf node.*/
int height(Node root)
{
if (root == null)
return 0;
else
{
/* compute height of each subtree */
int lheight = height(root.left);
int rheight = height(root.right);
/* use the larger one */
if (lheight > rheight)
return(lheight+1);
else return(rheight+1);
}
}
/* Print nodes at the given level */
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);
}
}
Any ideas?
Here's an implementation using while loop and two queues to keep track of all the nodes:
public String treeLevelOrder(Node root) {
StringBuilder result = new StringBuilder("");
Queue<Node> current = new LinkedList<>();
Queue<Node> other = new LinkedList<>();
if(root != null)
current.add(root);
while(!current.isEmpty()) {
while(!current.isEmpty()) {
Node node = current.remove();
result.append(",");
result.append(node.datum);
// adding children to the other queue
if(node.left != null)
other.add(node.left);
if(node.right != null)
other.add(node.right);
}
// swapping the queues
Queue<Node> temp = current;
current = other;
other = temp;
}
// building final string
if(result.length() == 0)
result.append("[");
else
result.setCharAt(0,'[');
result.append("]");
return result.toString();
}

Lowest Common Ancestor of a Binary Tree

This is a popular interview question and the only article I can find on the topic is one from TopCoder. Unfortunately for me, it looks overly complicated from an interview answer's perspective.
Isn't there a simpler way of doing this other than plotting the path to both nodes and deducing the ancestor? (This is a popular answer, but there's a variation of the interview question asking for a constant space answer).
A simplistic (but much less involved version) could simply be (.NET guy here Java a bit rusty, so please excuse the syntax, but I think you won't have to adjust too much). This is what I threw together.
class Program
{
static void Main(string[] args)
{
Node node1 = new Node { Number = 1 };
Node node2 = new Node { Number = 2, Parent = node1 };
Node node3 = new Node { Number = 3, Parent = node1 };
Node node4 = new Node { Number = 4, Parent = node1 };
Node node5 = new Node { Number = 5, Parent = node3 };
Node node6 = new Node { Number = 6, Parent = node3 };
Node node7 = new Node { Number = 7, Parent = node3 };
Node node8 = new Node { Number = 8, Parent = node6 };
Node node9 = new Node { Number = 9, Parent = node6 };
Node node10 = new Node { Number = 10, Parent = node7 };
Node node11 = new Node { Number = 11, Parent = node7 };
Node node12 = new Node { Number = 12, Parent = node10 };
Node node13 = new Node { Number = 13, Parent = node10 };
Node commonAncestor = FindLowestCommonAncestor(node9, node12);
Console.WriteLine(commonAncestor.Number);
Console.ReadLine();
}
public class Node
{
public int Number { get; set; }
public Node Parent { get; set; }
public int CalculateNodeHeight()
{
return CalculateNodeHeight(this);
}
private int CalculateNodeHeight(Node node)
{
if (node.Parent == null)
{
return 1;
}
return CalculateNodeHeight(node.Parent) + 1;
}
}
public static Node FindLowestCommonAncestor(Node node1, Node node2)
{
int nodeLevel1 = node1.CalculateNodeHeight();
int nodeLevel2 = node2.CalculateNodeHeight();
while (nodeLevel1 > 0 && nodeLevel2 > 0)
{
if (nodeLevel1 > nodeLevel2)
{
node1 = node1.Parent;
nodeLevel1--;
}
else if (nodeLevel2 > nodeLevel1)
{
node2 = node2.Parent;
nodeLevel2--;
}
else
{
if (node1 == node2)
{
return node1;
}
node1 = node1.Parent;
node2 = node2.Parent;
nodeLevel1--;
nodeLevel2--;
}
}
return null;
}
}
Constant space answer: (although not necessarily efficient).
Have a function findItemInPath(int index, int searchId, Node root)
then iterate from 0 .. depth of tree, finding the 0-th item, 1-th item etc. in both search paths.
When you find i such that the function returns the same result for both, but not for i+1,
then the i-th item in the path is the lowest common ancestor.
The main reason why the article's solutions are more complicated is that it is dealing with a two-stage problem- preprocessing and then queries- while from your question it sounds like you're only doing one query so preprocessing doesn't make sense. It's also dealing with arbitrary trees rather than binary trees.
The best answer will certainly depend on details about the tree. For many kinds of trees, the time complexity is going to be O(h) where h is the tree's height. If you've got pointers to parent nodes, then the easy "constant-space" answer is, as in Mirko's solution, to find both nodes' height and compare ancestors of the same height. Note that this works for any tree with parent links, binary or no. We can improve on Mirko's solution by making the height function iterative and by separating the "get to the same depth" loops from the main loop:
int height(Node n){
int h=-1;
while(n!=null){h++;n=n.parent;}
return h;
}
Node LCA(Node n1, Node n2){
int discrepancy=height(n1)-height(n2);
while(discrepancy>0) {n1=n1.parent;discrepancy--;}
while(discrepancy<0) {n2=n2.parent;discrepancy++;}
while(n1!=n2){n1=n1.parent();n2=n2.parent();}
return n1;
}
The quotation marks around "constant-space" are because in general we need O(log(h)) space to store the heights and the difference between them (say, 3 BigIntegers). But if you're dealing with trees with heights too large to stuff in a long, you likely have other problems to worry about that are more pressing than storing a couple nodes' heights.
If you have a BST, then you can easily take a common ancestor (usu. starting with root) and check its children to see whether either of them is a common ancestor:
Node LCA(Node n1, Node n2, Node CA){
while(true){
if(n1.val<CA.val & n2.val<CA.val) CA=CA.left;
else if (n1.val>CA.val & n2.val>CA.val) CA=CA.right;
else return CA;
}
}
As Philip JF mentioned, this same idea can be used in any tree for a constant-space algorithm, but for a general tree doing it this way will be really slow since figuring out repeatedly whether CA.left or CA.right is a common ancestor will repeat a lot of work, so you'd normally prefer to use more space to save some time. The main way to make that tradeoff would be basically the algorithm you've mentioned (storing the path from root).
It matters what kind of tree you are using. You can always tell if a node is the ancestor of another node in constant space, and the top node is always a common ancestor, so getting the Lowest Common Ancestor in constant space just requires iterating your way down. On a binary search tree this is pretty easy to do fast, but it will work on any tree.
Many different trade offs are relevant for this problem, and the type of tree matters. The problem tends is much easier if you have pointers to parent nodes, and not just to children (Mirko's code uses this)
See also:
http://en.wikipedia.org/wiki/Lowest_common_ancestor
The obvious solution, that uses log(n) space, (n is the number of nodes) is the algorithm you mentioned. Here's an implementation. In the worst case it takes O(n) time (imagine that one of the node you are searching common ancestor for includes the last node).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Node
{
private static int counter = 0;
private Node left = null;
private Node right = null;
public int id = counter++;
static Node constructTreeAux(int depth)
{
if (depth == 0)
return null;
Node newNode = new Node();
newNode.left = constructTree(depth - 1);
newNode.right = constructTree(depth - 1);
return newNode;
}
public static Node constructTree(int depth)
{
if (depth == 0)
return null;
Node root = new Node();
root.left = constructTreeAux(depth - 1);
root.right = constructTreeAux(depth - 1);
return root;
}
private List<Node> findPathAux(List<Node> pathSoFar, int searchId)
{
if (this.id == searchId)
{
if (pathSoFar == null)
pathSoFar = new List<Node>();
pathSoFar.Add(this);
return pathSoFar;
}
if (left != null)
{
List<Node> result = left.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
if (right != null)
{
List<Node> result = right.findPathAux(null, searchId);
if (result != null)
{
result.Add(this);
return result;
}
}
return null;
}
public static void printPath(List<Node> path)
{
if (path == null)
{
Console.Out.WriteLine(" empty path ");
return;
}
Console.Out.Write("[");
for (int i = 0; i < path.Count; i++)
Console.Out.Write(path[i] + " ");
Console.Out.WriteLine("]");
}
public override string ToString()
{
return id.ToString();
}
/// <summary>
/// Returns null if no common ancestor, the lowest common ancestor otherwise.
/// </summary>
public Node findCommonAncestor(int id1, int id2)
{
List<Node> path1 = findPathAux(null, id1);
if (path1 == null)
return null;
path1 = path1.Reverse<Node>().ToList<Node>();
List<Node> path2 = findPathAux(null, id2);
if (path2 == null)
return null;
path2 = path2.Reverse<Node>().ToList<Node>();
Node commonAncestor = this;
int n = path1.Count < path2.Count? path1.Count : path2.Count;
printPath(path1);
printPath(path2);
for (int i = 0; i < n; i++)
{
if (path1[i].id == path2[i].id)
commonAncestor = path1[i];
else
return commonAncestor;
}
return commonAncestor;
}
private void printTreeAux(int depth)
{
for (int i = 0; i < depth; i++)
Console.Write(" ");
Console.WriteLine(id);
if (left != null)
left.printTreeAux(depth + 1);
if (right != null)
right.printTreeAux(depth + 1);
}
public void printTree()
{
printTreeAux(0);
}
public static void testAux(out Node root, out Node commonAncestor, out int id1, out int id2)
{
Random gen = new Random();
int startid = counter;
root = constructTree(5);
int endid = counter;
int offset = gen.Next(endid - startid);
id1 = startid + offset;
offset = gen.Next(endid - startid);
id2 = startid + offset;
commonAncestor = root.findCommonAncestor(id1, id2);
}
public static void test1()
{
Node root = null, commonAncestor = null;
int id1 = 0, id2 = 0;
testAux(out root, out commonAncestor, out id1, out id2);
root.printTree();
commonAncestor = root.findCommonAncestor(id1, id2);
if (commonAncestor == null)
Console.WriteLine("Couldn't find common ancestor for " + id1 + " and " + id2);
else
Console.WriteLine("Common ancestor for " + id1 + " and " + id2 + " is " + commonAncestor.id);
}
}
}
The bottom up approach described here is an O(n) time, O(1) space approach:
http://www.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
Node *LCA(Node *root, Node *p, Node *q) {
if (!root) return NULL;
if (root == p || root == q) return root;
Node *L = LCA(root->left, p, q);
Node *R = LCA(root->right, p, q);
if (L && R) return root; // if p and q are on both sides
return L ? L : R; // either one of p,q is on one side OR p,q is not in L&R subtrees
}

Categories

Resources