I was working on a coding problem which required me to find the path to a node. Using recursion and DFS, this was quite easy.
public ArrayList<Integer> ancestorsList = new ArrayList<Integer>();
public boolean printAncestors(TreeNode root, int nodeData) {
if (root == null) return false;
if (root.data == nodeData) return true;
boolean found = printAncestors(root.left, nodeData) || printAncestors(root.right, nodeData);
if (found) ancestorsList.add(root.data);
return found;
}
However, I always had trouble converting a recursive algorithm to a iterative one even though recursion is just using the program stack. I played around with the code a bit, but it seems like the iterative algorithm would require a map that links the child node to it's parent in order to backtrack if the node is found.
I was just wondering if there was a simpler way, or if the simplest way really was using a map that linked the parent and child nodes so you could backtrack.
Thanks!
In order to make code simple,i assume the node is different each other by value.
Basic data structure:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class TreeNode implements Comparator<TreeNode> {
private int value;
private TreeNode left;
private TreeNode right;
#Override
public int compare(TreeNode o1, TreeNode o2) {
return o1.getValue() - o2.getValue();
}
}
The code to find path:
private static List<TreeNode> findPath(TreeNode root, int val) {
if (null == root) {
return Collections.emptyList();
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
List<TreeNode> path = new ArrayList<>();
while (!stack.isEmpty()) {
TreeNode top = stack.pop();
path.add(top);
// check the value
if (top.getValue() == val) {
break;
}
if (top.getRight() != null) {
stack.push(top.getRight());
}
if (top.getLeft() != null) {
stack.push(top.getLeft());
}
// if the node is leaf,we need rollback the path
if (null == top.getLeft() && null == top.getRight()) {
if (stack.isEmpty()) {
path.clear();
break;
}
TreeNode nextTop = stack.peek();
for (int i = path.size() - 1; i >= 0; i--) {
if (path.get(i).getRight() == nextTop || path.get(i).getLeft() == nextTop) {
path = path.subList(0, i + 1);
break;
}
}
}
}
return path;
}
Test Case:
#Test
public void test_findPath() {
TreeNode treeNode8 = new TreeNode(8, null, null);
TreeNode treeNode9 = new TreeNode(9, null, null);
TreeNode treeNode10 = new TreeNode(10, null, null);
TreeNode treeNode4 = new TreeNode(4, treeNode8, null);
TreeNode treeNode5 = new TreeNode(5, treeNode9, treeNode10);
TreeNode treeNode2 = new TreeNode(2, treeNode4, treeNode5);
TreeNode treeNode1 = new TreeNode(1, treeNode2, null);
List<TreeNode> path = TreeNodeService.findPath(treeNode1, 10);
Assert.assertEquals(path.size(),4);
Assert.assertEquals(path.get(0).getValue(),1);
Assert.assertEquals(path.get(1).getValue(),2);
Assert.assertEquals(path.get(2).getValue(),5);
Assert.assertEquals(path.get(3).getValue(),10);
}
Note: If you tree has two or more nodes has the same value,you need to change some codes.You can try youself.
Related
The BST is as follows:
50 (Root 1)
/ \
40 80 (Root 2)
/ \
20 41
As you can see there are 2 root's that I am dealing with. I have tried the following code which does return the height of the tree from ROOT 1. I don't quite exactly know how to return the height from ROOT 2.
Any help on how to solve would be appreciated.
// Java program to find height of tree
// A binary tree node
class Node
{
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree
{
Node root;
int maxDepth(Node node)
{
if (node == null)
return 0;
else
{
/* compute the depth of each subtree */
int lDepth = maxDepth(node.left);
int rDepth = maxDepth(node.right);
/* use the larger one */
if (lDepth > rDepth)
return (lDepth + 1);
else
return (rDepth + 1);
}
}
/* Driver program to test above functions */
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
System.out.println("Height of tree is : " +
tree.maxDepth(tree.root));
}
Your function for finding max depth seems like to work correctly. So fixing this issue is pretty simple.
System.out.println("Height of tree is : " +
tree.maxDepth(tree.root));
The above line prints out the height of the tree starting at the root. But if you were to start at "root 2" as you call it you would need to modify this line to start at the correct node.
System.out.println("Height of tree is : " +
tree.maxDepth(tree.root.right));
Adding an item to a Tree class should be made through a insert method.
And we can make the Node class private, it is used only by BinaryTree class.
A better data structure for a tree should be like the following, which has public insert and height methods.
public class BinaryTree {
private class Node {
private int value;
private Node left;
private Node right;
private Node(int value) {
this.value = value;
}
}
private Node root;
public void insert(int item) {
var node = new Node(item);
if (root == null) {
root = node;
return;
}
var current = root;
while (true) {
if (item < current.value) {
if (current.left == null) {
current.left = node;
break;
}
current = current.left;
} else {
if (current.right == null) {
current.right = node;
break;
}
current = current.right;
}
}
}
public int height() {
return height(root);
}
private int height(Node root) {
if (root == null)
return -1;
if (isLeaf(root))
return 0;
return 1 + Math.max(height(root.left), height(root.right));
}
private boolean isLeaf(Node node) {
return node.left == null && node.right == null;
}
}
And to use it, just add some values, and print the height.
It is way easier to insert an item with this tree class.
BinaryTree tree = new BinaryTree();
tree.insert(50);
tree.insert(40);
tree.insert(80);
tree.insert(20);
tree.insert(41);
System.out.println(tree.height());
I have to find and return the next larger node in the generic tree almost all testcases are running fine and giving correct output just one testcase is coming out wrong and it could be anything. I have debugged my program many times and could not figured out what bug that could be? Actually what I'm doing I'm comparing all the next larger nodes that recursion has fetched for me and comparing them with one another and ultimately find the right one? I'm stuck a little help would be appreciated.
Code
/* TreeNode structure
class TreeNode<T> {
T data;
ArrayList<TreeNode<T>> children;
TreeNode(T data){
this.data = data;
children = new ArrayList<TreeNode<T>>();
}
}*/
public static TreeNode<Integer> findNextLargerNode(TreeNode<Integer> root, int n){
if(root==null)
return root;
if(root.children.size()==0)
{
if(root.data>n)
{
return root;
}
else
return null;
}
TreeNode<Integer> count[] = new TreeNode[root.children.size()];
for(int i=0;i<root.children.size();i++)
{
count[i] = findNextLargerNode(root.children.get(i),n);
}
int nextLarger=Integer.MAX_VALUE;
TreeNode<Integer> next = null;
for(int i=0;i<count.length;i++)
{
if(count[i]!=null)
{
if(count[i].data>n && count[i].data<nextLarger)
{
nextLarger = count[i].data;
next = count[i];
}
}
}
if(next!=null)
{
if(root.data>n && root.data<next.data)
return root;
else
return next;
}
else
return null;
}
I see one extreme test which could fail: if the correct answer is a node that has as data Integer.MAX_VALUE, then your code will return null instead of that node.
A solution with the least change to your code, is to replace:
count[i].data<nextLarger
with:
count[i].data<=nextLarger
This way you are sure to give next a non-null value even if count[i].data is Integer.MAX_VALUE.
NB: If you would join both for loops into one, you would not need to use a count array, but just a single node variable.
Finally, I have found the bug in my code. It lies in the following segment.
if(next!=null)
{
if(root.data>n && root.data<next.data)
return root;
else
return next;
}
else
return null;
Suppose if next == null then else will get executed which will return the null. This is wrong because root can also be the next larger node so I have to check for that condition also
The correct version is :
if(next!=null)
{
if(root.data>n && root.data<next.data)
return root;
else
return next;
}
else
{
if(root.data>n)
return root;
else
return null;
}
Try
public class Test {
class TreeNode<T> {
T data;
List<TreeNode<T>> children;
TreeNode(T data) {
this.data = data;
children = new ArrayList<TreeNode<T>>();
}
public TreeNode<T> findNextNode(T n,Comparator<T> comp) {
if (comp.compare(data , n) < 0) {
return this;
}
if (children.size() == 0) {
return null;
}
for (int i = 0; i < children.size(); i++) {
TreeNode<T> node= children.get(i).findNextNode(n,comp);
if(node!=null)return node;
}
return null;
}
}
Explanation:
Tests
To show some errors in your code I provide a test in testForYourCode (see below). The test returns an unexpected result. The second child with a value of 4 wins which is wrong.
In TreeNode<T>.findNextNode I provide a 'refactored' version. Not sure if it does what you have asked for. The two tests testForModifiedCodeand testForModifiedCodeComplex show how the refactored version behaves.
Generic
Instead of writing a function that can deal only with TreeNode<Integer> I decided to write a generic function that works on all kind of types.
Comparison
The actual comparison is delegated to a Comparator object. An instance of a Comparator must be passed to the findNextNode method. This can be done on-the-fly using Java 8 lambda syntax, e.g. (a,b)->{return b-a;}. This adds some flexibility to the implementation. By changing the comparator you can also search for the 'next lesser node' using (a,b)->{return a-b;}.
What it does
If the entry node fulfills the criteria defined by the Comparator.compare implementation the algorithm stops. Otherwise a deep search is performed starting at the first child node (and so forth). As soon as the node matches the comparison criteria the algorithm stops. If no node matches, null is returned.
package stack43210199;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.junit.Assert;
public class Test {
class TreeNode<T> {
T data;
List<TreeNode<T>> children;
TreeNode(T data) {
this.data = data;
children = new ArrayList<TreeNode<T>>();
}
public TreeNode<T> findNextNode(T n,Comparator<T> comp) {
if (comp.compare(data , n) < 0) {
return this;
}
if (children.size() == 0) {
return null;
}
for (int i = 0; i < children.size(); i++) {
TreeNode<T> node= children.get(i).findNextNode(n,comp);
if(node!=null)return node;
}
return null;
}
}
#org.junit.Test
public void testForYourCode() {
TreeNode<Integer> root = buildNode(0);
TreeNode<Integer> firstChild = buildNode(5);
TreeNode<Integer> secondChild = buildNode(4);
TreeNode<Integer> thirdChild = buildNode(5);
root.children.add(firstChild);
root.children.add(secondChild);
root.children.add(thirdChild);
//Arrg - not as expected
Assert.assertEquals(secondChild, findNextLargerNode(root, 0));
}
#org.junit.Test
public void testForModifiedCode() {
TreeNode<Integer> root = buildNode(2);
TreeNode<Integer> firstChild = buildNode(5);
TreeNode<Integer> secondChild = buildNode(4);
TreeNode<Integer> thirdChild = buildNode(5);
TreeNode<Integer> fourthChild = buildNode(1);
root.children.add(firstChild);
root.children.add(secondChild);
root.children.add(thirdChild);
thirdChild.children.add(fourthChild);
//find next greater
Assert.assertEquals(firstChild, root.findNextNode(2,(a,b)->{return b-a;}));
//find next lesser
Assert.assertEquals(fourthChild, root.findNextNode(2,(a,b)->{return a-b;}));
}
#org.junit.Test
public void testForModifiedCodeComplex() {
TreeNode<Integer> root = buildNode(2);
TreeNode<Integer> firstChild = buildNode(2);
TreeNode<Integer> secondChild = buildNode(4);
TreeNode<Integer> thirdChild = buildNode(5);
TreeNode<Integer> fourthChild = buildNode(1);
TreeNode<Integer> sixthChild = buildNode(8);
firstChild.children.add(fourthChild);
firstChild.children.add(sixthChild);
root.children.add(firstChild);
root.children.add(secondChild);
root.children.add(thirdChild);
//find next greater
Assert.assertEquals(sixthChild, root.findNextNode(2,(a,b)->{return b-a;}));
//find next lesser
Assert.assertEquals(fourthChild, root.findNextNode(2,(a,b)->{return a-b;}));
}
private TreeNode<Integer> buildNode(int i) {
return new TreeNode<Integer>(new Integer(i));
}
public static TreeNode<Integer> findNextLargerNode(TreeNode<Integer> root, int n) {
if (root == null)
return root;
if (root.children.size() == 0) {
if (root.data > n) {
return root;
}
else
return null;
}
TreeNode<Integer> count[] = new TreeNode[root.children.size()];
for (int i = 0; i < root.children.size(); i++) {
count[i] = findNextLargerNode(root.children.get(i), n);
}
int nextLarger = Integer.MAX_VALUE;
TreeNode<Integer> next = null;
for (int i = 0; i < count.length; i++) {
if (count[i] != null) {
if (count[i].data > n && count[i].data < nextLarger) {
nextLarger = count[i].data;
next = count[i];
}
}
}
if (next != null) {
if (root.data > n && root.data < next.data)
return root;
else
return next;
} else {
if (root.data > n)
return root;
else
return null;
}
}
}
A TreeNode would normally look like this.
class TreeNode<T extends Comparable<T>> {
T data;
TreeNode<T> left, right;
TreeNode(T data){
this.data = data;
}
public TreeNode<T> findNextLargerNode(T t) {
if (data.compareTo(t) <= 0)
return right == null ? null : right.findNextLargerNode(t);
T found = left == null ? null : left.findNextLargerNode(t);
return found == null ? this : found;
}
}
I was doing this exercice:
Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. Example input: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 output: 3 -> 1 -> 2 -> 10 -> 5 -> 5 -> 8
I found it hard to find a solution for Singly linked list (that created by my own, not using library), I would like to know if there is uncessary code blocks in my code and is there a way to avoid putting in two lists and then merge? because it seems to have very slow performance like that.
public CustomLinkedList partition(CustomLinkedList list, int x) {
CustomLinkedList beforeL = new CustomLinkedList();
CustomLinkedList afterL = new CustomLinkedList();
LinkedListNode current = list.getHead();
while (current != null) {
if (current.getData() < x) {
addToLinkedList(beforeL, current.getData());
} else {
addToLinkedList(afterL, current.getData());
}
// increment current
current = current.getNext();
}
if (beforeL.getHead() == null)
return afterL;
mergeLinkedLists(beforeL, afterL);
return beforeL;
}
public void addToLinkedList(CustomLinkedList list, int value) {
LinkedListNode newEnd = new LinkedListNode(value);
LinkedListNode cur = list.getHead();
if (cur == null)
list.setHead(newEnd);
else {
while (cur.getNext() != null) {
cur = cur.getNext();
}
cur.setNext(newEnd);
cur = newEnd;
}
}
public void mergeLinkedLists(CustomLinkedList list1, CustomLinkedList list2) {
LinkedListNode start = list1.getHead();
LinkedListNode prev = null;
while (start != null) {
prev = start;
start = start.getNext();
}
prev.setNext(list2.getHead());
}
CustumLinkedList contains two attributes: -LinkedListNode which is the head and an int which is the size.
LinkedListNode contains two attributes: One of type LinkedListNode pointing to next node and one of type int: data value
Thank you.
The problem of your code is not merging two lists as you mentioned. It's wrong to use the word merge here because you're only linking up the tail of the left list with head of right list which is a constant time operation.
The real problem is - on inserting a new element on the left or right list, you are iterating from head to tail every time which yields in-total O(n^2) operation and is definitely slow.
Here I've wrote a simpler version and avoid iterating every time from head to insert a new item by keeping track of the current tail.
The code is very simple and is definitely faster than yours(O(n)). Let me know if you need explanation on any part.
// I don't know how your CustomLinkedList is implemented. Here I wrote a simple LinkedList node
public class ListNode {
private int val;
private ListNode next;
public ListNode(int x) {
val = x;
}
public int getValue() {
return this.val;
}
public ListNode getNext() {
return this.next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
public ListNode partition(ListNode head, int x) {
if(head == null) return null;
ListNode left = null;
ListNode right = null;
ListNode iterL = left;
ListNode iterR = right;
while(iter != null) {
if(iter.getValue() < x) {
iterL = addNode(iterL, iter.getValue());
}
else {
iterR = addNode(iterR, iter.getValue());
}
iter = iter.getNext();
}
// link up the left and right list
iterL.setNext(iterR);
return left;
}
public ListNode addNode(ListNode curr, int value) {
ListNode* newNode = new ListNode(value);
if(curr == null) {
curr = newNode;
} else {
curr.setNext(newNode);
curr = curr.getNext();
}
return curr;
}
Hope it helps!
If you have any list of data, access orderByX Method.
Hope it would help you.
public class OrderByX {
Nodes root = null;
OrderByX() {
root = null;
}
void create(int[] array, int k) {
for (int i = 0; i < array.length; ++i) {
root = insert(root, array[i]);
}
}
Nodes insert(Nodes root, int data) {
if (root == null) {
root = new Nodes(data);
} else {
Nodes tempNew = new Nodes(data);
tempNew.setNext(root);
root = tempNew;
}
return root;
}
void display() {
Nodes tempNode = root;
while (tempNode != null) {
System.out.print(tempNode.getData() + ", ");
tempNode = tempNode.getNext();
}
}
void displayOrder(Nodes root) {
if (root == null) {
return;
} else {
displayOrder(root.getNext());
System.out.print(root.getData() + ", ");
}
}
Nodes orderByX(Nodes root, int x) {
Nodes resultNode = null;
Nodes lessNode = null;
Nodes greatNode = null;
Nodes midNode = null;
while (root != null) {
if (root.getData() < x) {
if (lessNode == null) {
lessNode = root;
root = root.getNext();
lessNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(lessNode);
lessNode = root;
root = temp;
}
} else if (root.getData() > x) {
if (greatNode == null) {
greatNode = root;
root = root.getNext();
greatNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(greatNode);
greatNode = root;
root = temp;
}
} else {
if (midNode == null) {
midNode = root;
root = root.getNext();
midNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(midNode);
midNode = root;
root = temp;
}
}
}
resultNode = lessNode;
while (lessNode.getNext() != null) {
lessNode = lessNode.getNext();
}
lessNode.setNext(midNode);
while (midNode.getNext() != null) {
midNode = midNode.getNext();
}
midNode.setNext(greatNode);
return resultNode;
}
public static void main(String... args) {
int[] array = { 7, 1, 6, 2, 8 };
OrderByX obj = new OrderByX();
obj.create(array, 0);
obj.display();
System.out.println();
obj.displayOrder(obj.root);
System.out.println();
obj.root = obj.orderByX(obj.root, 2);
obj.display();
}
}
class Nodes {
private int data;
private Nodes next;
Nodes(int data) {
this.data = data;
this.next = null;
}
public Nodes getNext() {
return next;
}
public void setNext(Nodes next) {
this.next = next;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
I think that maintaining two lists is not an issue. It is possible to use a single list, but at the cost of loosing some of the simplicity.
The principal problem seems to be the addToLinkedList(CustomLinkedList list, int value) method.
It iterates throughout the entire list in order to add a new element.
One alternative is to always add elements at the front of the list. This would also produce a valid solution, and would run faster.
this is my class of A binary search tree:
public class BinarySearchTree {
class BSTNode {
int data;
BSTNode rchild;
BSTNode lchild;
//constructor
public BSTNode(int n){
data=n;
lchild=rchild=null;
}
}
private BSTNode root;
private int size;
public BinarySearchTree() {
root = null;
size = -1;
}
public boolean insert(int n) {
if (root == null)
root = new BSTNode(n);
else
insert(n, root);
return true;
}
private void insert(int n, BSTNode r) {
if (r.data > n)
if (r.lchild == null)
r.lchild = new BSTNode(n);
else
insert(n, r.lchild);
else
if (r.data < n)
if (r.rchild == null)
r.rchild = new BSTNode(n);
else
insert(n, r.rchild);
}
}
Actually I am finding a difficulty in writing a method that checks if my tree is a Complete Binary Tree. Can someone provide me with the solution please.
I will follow this definition:
Complete binary tree : Every level except the last level is completely filled and all the nodes are left justified.
You're going to have to modify this a bit for your your implementation of BSTNode, but I believe this should fit your needs. The basic idea is to recursively traverse the tree and make sure that the "complete" property is fulfilled for each subtree.
boolean checkBinaryTreeCompleteness(TreeNode root) {
if (root != null) {
if (root.right == null && root.left == null) {
return true;
}
if (root.right != null && root.left != null) {
return checkBinaryTreeCompleteness(root.left) && checkBinaryTreeCompleteness(root.right);
}
}
return false;
}
I came up with this code but it requires a global variable Rank. Is there any way I can solve this problem without having to have a global variable?
int Rank = 0;
public int inOrderTraversal(TreeNode node, int n){
if(node==null)
return 0;
int x=inOrderTraversal(node.left,n);
if(x!=0)return x;
Rank++;
if(n==Rank) return node.data;
int y=inOrderTraversal(node.right,n);
int c= x==0 ? y:x;
return c;
}
I am just trying to return the nth term in an in-order traversal of a binary tree.
You can pass a TraversalState object down the recursion invocation chain, and store the number of nodes that you visited in a variable there:
class TraversalState {
public int rank = 0;
}
...
public int inOrderTraversal(TreeNode node, int n, TraversalState ts){
if(node==null)
return 0;
int x=inOrderTraversal(node.left,n, ts);
ts.rank++;
if(n==ts.rank) return node.data;
int y=inOrderTraversal(node.right,n, ts);
int c= x==0 ? y:x;
return c;
}
Now your implementation is thread-safe, because it does not use "global" objects. Invoke it as follows:
int r = inOrderTraversal(myNode, targetN, new TraversalState());
The recursive approach is easy to understand, but if your tree shape defies expectation, then you're at the mercy of maximum stack depth here, which is likely to be more limiting that heap memory consumed by an explicitly allocated stack structure. Hence, it's better to invest the time in building an iterative walker.
First, define the structure for the tree nodes themselves:
public final class TreeNode {
public final int data;
public final TreeNode left, right;
public TreeNode(int data, TreeNode left, TreeNode right) {
this.data = data;
this.left = left;
this.right = right;
}
public TreeNode(int data) {
this(data, null, null);
}
}
We're going to want a way to react to events signaled during a depth-first walk through the tree. Returning true from these methods indicates that the visitor wishes for the walk to continue; returning false requests that the walk stop as soon as possible.
public abstract class Visitor {
public boolean visitPre(TreeNode node) {
return true;
}
public boolean visitMid(TreeNode node) {
return true;
}
public boolean visitPost(TreeNode node) {
return true;
}
}
Now, define the iterative in-order walk algorithm:
final class InOrder {
private InOrder() {}
private static final class Breadcrumb {
public final TreeNode node;
public final boolean rightIsNext; // Not a great name.
public Breadcrumb(TreeNode node, boolean rightIsNext) {
this.node = node;
this.rightIsNext = rightIsNext;
}
public static Breadcrumb goingLeft(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, true);
}
public static Breadcrumb goingRight(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, false);
}
}
public static <T extends Visitor> T walk(TreeNode root, T visitor) {
if (null == root ||
null == visitor)
throw new NullPointerException();
final Deque<Breadcrumb> stack = new ArrayDeque<Breadcrumb>();
if (!visitor.visitPre(root))
return visitor;
for (;;) {
for (TreeNode left = root.left;
null != left;
root = left, left = root.left) {
if (!visitor.visitPre(left))
return visitor;
stack.push(Breadcrumb.goingLeft(root));
}
if (!visitor.visitMid(root))
return visitor;
final TreeNode right = root.right;
if (null != right) {
if (!visitor.visitPre(right))
return visitor;
stack.push(Breadcrumb.goingRight(root));
root = right;
} else {
if (!visitor.visitPost(root))
return visitor;
// Go back up the tree until we find a node with an unexplored right child.
for (;;) {
if (stack.isEmpty())
return visitor;
final Breadcrumb breadcrumb = stack.pop();
if (breadcrumb.rightIsNext) {
if (!visitor.visitMid(breadcrumb.node)) {
return visitor;
}
if (null != breadcrumb.node.right) {
if (!visitor.visitPre(breadcrumb.node.right))
return visitor;
stack.push(Breadcrumb.goingRight(breadcrumb.node));
root = breadcrumb.node.right;
break;
}
}
if (!visitor.visitPost(breadcrumb.node))
return visitor;
}
}
}
}
}
Exercise the walk() function on a sample tree:
(1)
|
+-+-+
| |
(2) (5)
|
+-+-+
| |
(3) -
|
+-+-+
| |
- (4)
That is, there are five nodes, where both leaves with data 4 and 5 are right children.
final TreeNode root = new TreeNode(1,
new TreeNode(2,
new TreeNode(3,
null,
new TreeNode(4)),
null),
new TreeNode(5));
walk(root,
new Visitor() {
private final PrintStream ps = System.out;
#Override
public boolean visitPre(TreeNode node) {
trace(node, "Pre");
return true;
}
#Override
public boolean visitMid(TreeNode node) {
trace(node, "Mid");
return true;
}
#Override
public boolean visitPost(TreeNode node) {
trace(node, "Post");
return true;
}
private TreeNode trace(TreeNode node, String phase) {
ps.print(phase);
ps.print('(');
ps.print(node.data);
ps.println(')');
return node;
}
});
This prints the following:
Pre(1)
Pre(2)
Pre(3)
Mid(3)
Pre(4)
Mid(4)
Post(4)
Post(3)
Mid(2)
Post(2)
Mid(1)
Pre(5)
Mid(5)
Post(5)
Post(1)
Now, you asked for a convenient way to find the nth node encountered during an in-order walk. We'll write a function called findNthInOrder(), where the parameter n designates zero as the first node encountered whose left subtree has already been explored, one designates the second, and so on:
private static TreeNode findNthInOrder(TreeNode root, final int n) {
if (n < 0)
throw new IllegalArgumentException();
return walk(root,
new Visitor() {
public TreeNode found = null;
private int remaining = n + 1;
#Override
public boolean visitMid(TreeNode node) {
if (0 == --remaining) {
found = node;
return false;
}
return true;
}
}).found;
}
Calling this function on our sample tree yields the expected result:
final TreeNode nth = findNthInOrder(root, 3);
System.out.println(null != nth ? nth.data : "(none)");
This prints "1" to the console, which matches the previous tracing walk over the sample tree: the fourth (that is, the zero-based index 3, per the argument above) emitted "Mid" trace is for the root node bearing the data value of one.
In summary, consider building enough to formalize the concepts in play, so that you can write these specific queries more confidently atop a sound foundation.
public int inOrderTraversal(TreeNode node, AtomicInteger n){
if(node == null) return 0;
if(n == 0) return node.data;
int leftVal = inOrderTraversal(node.left, n.decrementAndGet());
if(n == 0) return node.data;
int rightVal = inOrderTraversal(node.right,n.decrementAndGet());
return leftVal == 0 ? rightVal : leftVal;
}
Or to use MutuableInt from Apache commons lang instead of AtomicInteger.