I have recently started learning computer science and Java coding and came across Traversal techniques. I am writing a Java code using Stack. I have been with this issue and couldn't find any solution. Is there anyway we can implement Post Order traversal using only one stack (without any extra data structure or extra space) ?
I have tried doing it and here is my code.
class node {
int data;
node left, right;
node(int val){
data = val;
left = right = null;
}
}
public class binaryt {
public static void postorder(node root) {
node current = root;
Stack<node> st = new Stack<>();
System.out.println();
System.out.print("Post-order : ");
while(current!=null) {
st.push(current);
current = current.left;
}
while(!st.empty()) {
current = st.pop();
if(current.right==null) {
System.out.print(current.data+" ");
current = null;
}
else {
st.push(current);
current = current.right;
while(current!=null) {
st.push(current);
current = current.left;
}
}
}
}
public static void main(String[] args) {
node root=null;
root = new node(12);
root.left = new node(8);
root.left.left = new node(2);
root.left.right = new node(9);
root.right= new node(16);
root.right.left= new node(13);
root.right.right= new node(18);
postorder(root);
}
}
I am unable to find what's wrong with the code as it is going in infinite loop. If anyone could help me, that would be huge favor.
Thank you so much.
The best way to learn these annoying algorithms is to suffer a bit and find your own solution that will stick in your brain - so you're doing the right thing. This one is always hard for me.
do
while(root != null)
push root.right to stack if not null
push root
root = root.left to stack
root = stack.pop()
if (root.right == stack.peek)
stack.pop()
push root to stack
root = root.right
else
print root
root = null;
while stack ! empty
Your Problem
So, there are probably a few general things wrong in the attempt you showed. But here's the one I'd fix first, then I think you'll be able to get the others:
You can't just go left down the whole tree to start with. You need to go left only after you check the right node and add it to the stack. Remember, a recursive implementation would already have the root/current frame existing, then it would call the left and right trees. So, that means the current frame goes last after the left and right calls finish. So, the function call stack logically holds the left sub-tree, then the right-sub-tree, then the current frame.
This is what is happening in your code :
first you are pushing 12,8 and 2 in the Stack
Then there is no left child for 2 , so you come to while
now 2 is popped out , and it has no right child, so now two values in stack 8,12
Next comes 8 it has a right child, you are pushing 8 into Stack again.
Now you are taking 9 as current and pushing it into Stack.
Now you are checking left of 9 which is null.
so you are again starting with while(!st.empty()) { loop which has elements 9, 8,12
again same thing repeats and your while loop never ends
you can also see on console : Post-order : 2 9 9 9 9 ..... Continues
So that is the issue.
Below is a solution :
public static void postorderIter( node root) {
if( root == null ) return;
Stack<node> s = new Stack<node>( );
node current = root;
while( true ) {
if( current != null ) {
if( current.right != null )
s.push( current.right );
s.push( current );
current = current.left;
continue;
}
if( s.isEmpty( ) )
return;
current = s.pop( );
if( current.right != null && ! s.isEmpty( ) && current.right == s.peek( ) ) {
s.pop( );
s.push( current );
current = current.right;
} else {
System.out.print( current.data + " " );
current = null;
}
}
}
Here's an example that relies on recursion to make it more readable.
public static void postorder(node root) {
Stack<node> nodes = new Stack<>();
node curr = root;
postOrderRecursive(curr, nodes);
int size = nodes.size();
while(size > 0){
System.out.println(nodes.elementAt(0).data);
nodes.remove(0);
size = nodes.size();
}
}
private static void postOrderRecursive(node n, Stack<node> nodes){
if(n.left != null)
postOrderRecursive(n.left, nodes);
if(n.right != null)
postOrderRecursive(n.right, nodes);
nodes.push(n);
}
Output given your initialization:
2
9
8
13
18
16
12
Related
I am struggling to figure out how to code a recursive algorithm to count the number of leaves in a Binary Tree (not a complete tree). I get as far as traversing to the far most left leaf and don't know what to return from there. I am trying to get the count by loading the leaves into a list and getting the size of that list. This is probably a bad way to go about the count.
public int countLeaves ( ) {
List< Node<E> > leafList = new ArrayList< Node<E> >();
//BinaryTree<Node<E>> treeList = new BinaryTree(root);
if(root.left != null)
{
root = root.left;
countLeaves();
}
if(root.right != null)
{
root = root.right;
countLeaves();
}
if(root.left == null && root.right == null)
{
leafList.add(root);
}
return();
}
Elaborating on #dasblinkenlight idea. You want to recursively call a countleaves on root node & pass back the # to caller. Something on the following lines.
public int countLeaves() {
return countLeaves(root);
}
/**
* Recursively count all nodes
*/
private static int countLeaves (Node<E> node) {
if(node==null)
return 0;
if(node.left ==null && node.right == null)
return 1;
else {
return countLeaves(node.left) + countLeaves(node.right);
}
}
Edit: It appears, a similar problem was previously asked counting number of leaf nodes in binary tree
The problem with your implementation is that it does not restore the value of member variable root back to the state that it had prior to entering the method. You could do it by storing the value in a local variable, i.e.
Node<E> oldRoot = root;
... // your method goes here
root = oldRoot;
However, a better approach is to take Node<E> as an argument, rather than relying on a shared variable:
public int countLeaves() {
return countLeaves(root);
}
private static int countLeaves (Node<E> node) {
... // Do counting here
}
I'm a little confused why my code doesn't insert nodes past the first one. say I wanted to insert (5,4) after (7,2) using the code below; in this case the very first condition is triggered, isVertical and p.x() < node.point.x(). The way I see it since node.left is null, I exit the loop and since node holds a reference node.left based on the latest assignment, I should be able to use node to insert a new tree leaf. Am I not seeing this right? Is node not really a reference to node.left? Sorry if this is a dumb question, I am still just a little shaky with references.
public void insert(Point2D p) {
if (p == null) {
throw new java.lang.NullPointerException();
}
if (size == 0) {
root = new Node(p);
size++;
return;
}
Node node = root;
while (node != null) {
// sink
if (node.isVertical()) {
if (p.x() < node.point.x()) {
node = node.left; // go left
} else {
node = node.right; // go right
}
} else if (node.isHorizontal()) {
if (p.y() < node.point.y()) {
node = node.left; // go left
} else {
node = node.right; // go right
}
}
}
node = new Node(p);
}
You're just assigning new Node(p) to a local variable node, whose value is lost as soon as the function returns. To change the existing tree, your assignment should have the form node.left = new Node(p); or node.right = new Node(p).
void deleteEven() {
boolean con = false;
Node add;
Node move;
move = head;
if (move.data % 2 == 0) {
head = move.next;
con = true;
}
add = move;
move = move.next;
while (move != null) {
if (move.data % 2 == 0 ) {
add.next = move.next;
con = true;
}
add = move;
move = move.next;
}
if (!con)
System.out.println("No even numbers in list");
}
It works for every node except the tail.
if linked list is [5,4,3,2,2]
the result is [5,3,2]
How to fix that?
The problem is not with the tail node. The problem is with two even nodes in a row irrespective of where they are in the list. When the current node is even you are moving your pointer to the previous node (add) to the current node even though you have just removed it. For the second even node your add.next = move.next statement changes next for the node you have just removed.
The simplest solution is to only move add if the node is not even:
if (move.data % 2 == 1) {
add.next = move.next;
con = true;
} else {
add = move.next;
}
You could simplify your code quite a bit by getting rid of add altogether and just looking one node ahead of move:
while (move.next != null) {
if (move.next.data % 2 == 0) {
move.next = move.next.next;
con = true;
} else {
move = move.next;
}
}
And a programming tip for you: have several test cases before trying to diagnose a problem. I have found it's very easy to jump to an incorrect conclusion based on a small number of test cases and often expanding the range will make the problem clearer. That is one of the (many) reasons that test driven development works as well as it does.
Let's create service Node for attaching other nodes.
Then loop through the list and copy the references in a new list (new Node are not created):
void deleteEven() {
Node tmpHead = new Node(0, null);
Node tmpCopy = tmpHead;
Node tmp = head;
while (tmp != null) {
if (tmp.data % 2 == 1) {
tmpCopy.next = tmp;
tmpCopy = tmpCopy.next;
}
tmp = tmp.next;
}
tmpCopy.next = null;
head = tmpHead.next;
}
Suppose what Node is:
class Node {
int data;
Node next;
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
}
I have a huffman binary tree that starts with an empty node a.
A points to a left node and a right node, which also point to left and right nodes. Is it possible to set the parent nodes for each node recursively after having this tree?
This is the code I am thinking:
public Node setParents(Node n)
{
if(n.getZero() == null && n.getOne() == null)
{
return n;
}
Node a = setParents(n.getZero()); // Zero being left
a.setParent(n);
Node b = setParents(n.getOne()); // One being right.
b.setParent(n);
}
Here is how I am currently creating the tree by using a priority queue with values sorted least to greatest.
public Node createTree(PriorityQueue<Node> pq)
{
while(pq.size() > 1)
{
Node n = new Node();
Node a = pq.poll();
if(pq.size() > 0)
{
Node b = pq.poll();
n = new Node(a.getFrequency() + b.getFrequency());
n.setZero(a);
a.setWhich(0);
a.setParent(n);
n.setOne(b);
b.setWhich(1);
b.setParent(n);
}
else
{
n = new Node(a.getFrequency());
n.setZero(a);
a.setWhich(0);
n.setParent(n);
n.setOne(null);
}
pq.add(n);
}
Node n = pq.poll();
n.setParent(null);
setParents(n.getZero());
setParents(n.getOne());
return n;
}
I just need to make sure each node has a parent, which I don't know where to start from here.. Any help?
Some comments to your code that may help
1 . Do not use getters and setters in your study samples for simple assignments and reads, they are hard to understand.
2 . If you prepare some object do not mix this preparation with others
n.setZero(a);
a.setWhich(0);
a.setParent(n);
n.setOne(b);
3 . From what I understand there is a chance to get NPE
if(pq.size() > 0) {
Node b = pq.poll();
}
}
Node n = pq.poll();
n.setParent(null); <- n can be null
4 . Java has nice feature called Enums for this
a.setWhich(0);
b.setWhich(1);
Here is how to set parents starting from the root
public void fixParents(Node parentNode)
{
if (parentNode.zero != null) {
parentNode.zero.parent = parentNode;
fixParents(parentNode.zero);
}
if (parentNode.one != null) {
parentNode.one.parent = parentNode;
fixParents(parentNode.one);
}
}
UPD
One more thought. You set parents in your tree building function. So you should just check that parents are correct but not re-setting them.
public void checkParents(Node parentNode) throws Exception
{
if (parentNode.zero != null) {
if (parentNode.zero.parent != parentNode) {
throw new Exception( here include info about the parentNode.zero );
}
checkParents(parentNode.zero);
}
if (parentNode.one != null) {
if (parentNode.one.parent != parentNode) {
throw new Exception( here include info about the parentNode.one );
}
checkParents(parentNode.one);
}
}
My inputs results 24, 4, 2, 3, 9, 10, 32, and I am getting following result 2, 3, 4, 24.
I am using a stack. When I have manually checked this program the node is not going through else if at 4 on stack, even if has right sub tree.
public void inorderNonRcursive(Node root){
Stack s = new Stack();
Node node = root;
Node k;
int c=0;
if(node != null) {
s.push(node);
}
while(!s.stack.isEmpty()) {
//node=(Node) s.stack.get(s.stack.size()-1);
System.out.println("first condition" + (node.getleft() != null && (node.getVisited() == false)) + "second condi" + (node.getRight() != null));
if(node.getleft() != null && (node.getVisited() == false)) {
node = node.getleft();
s.push(node);
System.out.println(" from 1 "+(++c));
} else if(node.getRight() != null) {
k = s.pop();
System.out.println(k.getvalue());
node=node.getRight();
s.push(node);
System.out.println(" from 2 "+(++c));
} else {
k = s.pop();
System.out.println(k.getvalue());
System.out.println(" from 3 "+(++c));
}
}
}
To me, there are two problems in the design:
The algorithm seems to be the recursive one adapted for iteration and
The Node class knows about being visited.
Here is a different solution (you will need to adapt it a bit):
// Inorder traversal:
// Keep the nodes in the path that are waiting to be visited
Stack s = new Stack();
// The first node to be visited is the leftmost
Node node = root;
while (node != null)
{
s.push(node);
node = node.left;
}
// Traverse the tree
while (s.size() > 0)
{
// Visit the top node
node = (Node)s.pop();
System.out.println((String)node.data);
// Find the next node
if (node.right != null)
{
node = node.right;
// The next node to be visited is the leftmost
while (node != null)
{
s.push(node);
node = node.left;
}
}
}
Referring back to my first comments, you don't say you wrote pseudo code and tested it. I think this a key step in writing new algorithms.
This looks like a class exercise, designed to help you understand binary trees.
Before you write any code, draw a picture of your tree, with a value at each node, such as "A", "B", "C", etc. Then starting from the root node, see what you need to do to visit each node in order. Write what you have learned in pseudo code, and test it by doing what it says. Make sure you test all the different cases you can think of for each node (you should have at least three). Put about seven nodes in your tree.
Now you can start on your code. Type in your pseudo code as comments, then insert your Java code in between each comment.
Enjoy :-)