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;
}
}
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 testForModifiedCode
and testForModifiedCodeComplex
show how the refactored
version behaves.
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.
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, eg (a,b)->{return ba;}
. This adds some flexibility to the implementation. By changing the comparator you can also search for the 'next lesser node' using (a,b)->{return ab;}
.
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;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.