I am creating a program that inserts a character (number/letter) into a binary tree. So far, I'm able to produce an output but it's not what I expected. These are the problems I'm encountering:
The insert method is not able to print the correct height of the tree. I am not sure where I should insert my height++; statement to get the correct output.
The insert method is only able to add nodes to the right.
Expected Output: ht=3 [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]]
My Output: ht=4 [K=3 R=[K=1 R=[K=2 R=[K=5 R=[K=4]]]]
(all nodes are only added to the right 'R')
Here are my classes for reference:
Main Class
BST<Character> bst = new BST<>();
bst.insert('3');
bst.insert('1');
bst.insert('2');
bst.insert('5');
bst.insert('4');
System.out.println("ht=" + bst.height + " " + bst.toString());
BST Class - where the insert method is declared
public class BST<T> extends BT<T> {
// insert() method
public void insert(char k)
{
if (root == null) {
root = new BTNode(k);
return;
}
BTNode<T> n = root;
BTNode<T> p = null; // parent
while (n != null) {
p = n;
if (k < n.value) {
n = n.left;
} else {
n = n.right;
}
}
if (k < p.value) {
p.left = new BTNode(k);
} else {
p.right = new BTNode(k);
height++; // adds 1 to height when a new level is made
}
}
}
BTNode Class
public class BTNode<T> {
T info;
int value, level;
BTNode<T> left, right;
public BTNode(T el) {
this(el, null, null);
}
public BTNode(T el, BTNode<T> l, BTNode<T> r) {
info = el;
left = l;
right = r;
}
}
BT Class - where the toString method is declared
public class BT<T> {
BTNode<T> root = null;
int height = 0;
public BT() {
BTNode<T> node = new BTNode("");
}
// other methods
// toString()
public String toString() {
return toString(root);
}
public String toString(BTNode<T> n) {
String s = "";
if (n == null) {
return "";
}
if (n != null) {
s = "[K=" + n.info;
if (n.left != null) {
s = s + " L=" + toString(n.left) + "]";
}
if (n.right != null) {
s = s + " R=" + toString(n.right) + "]";
}
}
return s;
}
}
Hope you can help me out, thanks!
You have quite a few issues in your code. I'll list a few immediate items but you really will need to learn to use an interactive debugger and unit testing to resolve the sorts of issues you are seeing.
You refer to the value field in BTNode in your comparison but it is never set. You should really be referring to info (which is the actual data in the node).
But given info is a generic type you can't use standard comparison operators. Instead you'll need to define it as <T extends Comparable<T>> and then use n.info.compareTo(k) > 0.
The key passed into insert should also be of type T
Which means the other classes also need to ensure T extends Comparable.
Height is only incremented when nodes are added to the right which makes no sense.
Height needs to be increased only when a node is inserted further from the root than the current maximum. Something like the following:
int depth = 0;
while (n != null) {
depth++;
p = n;
...
}
depth++;
if (depth > height)
height = depth;
You should get used to making your fields private and accessing them through getters. In your case a compareValue method would likely make sense.
Related
I need to loop in a tree to get all possible paths, the problem in my code that i get just the first path!
example:
In the figure, there are 2 paths t handle: 1-2-3-4-5-6 and 1-2-3-7-8 , but i couldn't get both, i have just retrieved 1-2-3-4-5-6 !
my code:
In main:
for (String key : synset.keySet()) { // looping in a hash of Concept and it's ID
System.out.println("\nConcept: " + key + " " + synset.get(key));
List<Concept> ancts = myOntology.getConceptAncestors(myOntology.getConceptFromConceptID(synset.get(key))); // this function retreives the root of any node.
for (int i = 0; i < ancts.size(); i++) {
System.out.print(ancts.get(i).getConceptId() + " # ");
System.out.print(getChilds(ancts.get(i).getConceptId()) + " -> "); // here, the recursive function is needed to navigate into childs..
}
System.out.println("");
}
Rec. function:
public static String getChilds(String conId)
{
List<Concept> childs = myOntology.getDirectChildren(myOntology.getConceptFromConceptID(conId)); // get all childs of a node
if(childs.size() > 0)
{
for (int i = 0; i < childs.size(); i++) {
System.out.print( childs.size() + " ~ " + childs.get(i).getConceptId() + " -> ");
return getChilds(childs.get(i).getConceptId());
}
}
else
return "NULL";
return "final";
}
I didn't really see enough of your code to use the classes that you have defined. So I went for writing my own working solution.
In the following code, the problem is solved using recursion:
public class TreeNode {
private String id;
private TreeNode parent;
private List<TreeNode> children;
public TreeNode(String id) {
this.id = id;
this.children = new LinkedList<>();
}
public void addChild(TreeNode child) {
this.children.add(child);
child.setParent(this);
}
public List<TreeNode> getChildren() {
return Collections.unmodifiableList(this.children);
}
private void setParent(TreeNode parent) {
this.parent = parent;
}
public TreeNode getParent() {
return this.parent;
}
public String getId() {
return this.id;
}
}
public class TreePaths {
private static List<List<TreeNode>> getPaths0(TreeNode pos) {
List<List<TreeNode>> retLists = new ArrayList<>();
if(pos.getChildren().size() == 0) {
List<TreeNode> leafList = new LinkedList<>();
leafList.add(pos);
retLists.add(leafList);
} else {
for (TreeNode node : pos.getChildren()) {
List<List<TreeNode>> nodeLists = getPaths0(node);
for (List<TreeNode> nodeList : nodeLists) {
nodeList.add(0, pos);
retLists.add(nodeList);
}
}
}
return retLists;
}
public static List<List<TreeNode>> getPaths(TreeNode head) {
if(head == null) {
return new ArrayList<>();
} else {
return getPaths0(head);
}
}
}
To use the above code, a tree must be constructed using the TreeNode class. Start off by creating a head TreeNode, then add child nodes to it as required. The head is then submitted to the TreePaths getPaths static function.
After getPaths checks for null, the internal getPaths0 function will be called. Here we follow a depth first approach by trying to get to all leaf nodes as soon as possible. Once a leaf node is found, a List only containing this leaf node will be created and returned inside the list collection. The parent of this leaf node will then be added to the beginning of the list, which will again be put into a list collection. This will happen for all children of the parent.
In the end, all possible paths will end up in a single structure. This function can be tested as follows:
public class TreePathsTest {
TreeNode[] nodes = new TreeNode[10];
#Before
public void init() {
int count = 0;
for(TreeNode child : nodes) {
nodes[count] = new TreeNode(String.valueOf(count));
count++;
}
}
/*
* 0 - 1 - 3
* - 4
* - 2 - 5
* - 6
* - 7 - 8
* - 9
*/
private void constructBasicTree() {
nodes[0].addChild(nodes[1]);
nodes[0].addChild(nodes[2]);
nodes[1].addChild(nodes[3]);
nodes[1].addChild(nodes[4]);
nodes[2].addChild(nodes[5]);
nodes[2].addChild(nodes[6]);
nodes[2].addChild(nodes[7]);
nodes[7].addChild(nodes[8]);
nodes[7].addChild(nodes[9]);
}
#Test
public void testPaths() {
constructBasicTree();
List<List<TreeNode>> lists = TreePaths.getPaths(nodes[0]);
for(List<TreeNode> list : lists) {
for(int count = 0; count < list.size(); count++) {
System.out.print(list.get(count).getId());
if(count != list.size() - 1) {
System.out.print("-");
}
}
System.out.println();
}
}
}
This will print out:
0-1-3
0-1-4
0-2-5
0-2-6
0-2-7-8
0-2-7-9
Note: The above is enough for manual testing, but the test function should be modified to do proper assertions for proper automated unit testing.
maybe this code segment in getChilds() exist problem:
for (int i = 0; i < childs.size(); i++) {
System.out.print( childs.size() + " ~ " + childs.get(i).getConceptId() + " -> ");
return getChilds(childs.get(i).getConceptId());
}
the for loop cant play a role, it always return getChilds(childs.get(0).getConceptId());
maybe this is not what you want.
One simple way.
All you need is a tree traversal and little bit of custom code.
Have a list called tempPath. you can take it as an argument or a global variable.
Do a tree traversal(eg. inorder). Whenever you are at a node add this to tempPath list at the end and when you are done with this node remove the node from the end of tempPath.
whenever you encounter a leaf, you have one full path from root to leaf which is contained in tempPath. you can either print or copy this list value into another data structure.
I'm struggling to understand why this class is not functioning. It was part of an assignment for a course on Data Structures(EDIT: The deadline for the assignment has passed, I just want to figure it out...). The node is part of an AVL tree built upon a BST and the way I chose to implement it is by creating methods within my Node class to find the Balance factor and height.
The class is structured as follows:
public class Node<T extends Comparable<? super T>> {
public T data;
public Node left;
public Node right;
public Node(T IN) {
data = IN;
}
public Node(T IN, Node L, Node R) {
this(IN);
left = L;
right = R;
}
#Override
public String toString() {
return data.toString();
}
#Override
public Node clone() {
return new Node(this.data) ;
}
public int getHeight() {
return getHeight(this) ;
}
public int getBF() {
//Calculate BF
int balanceFactor = 0;
if (right != null && left != null)
balanceFactor = getHeight(right) - getHeight(left);
else if (left != null) {
balanceFactor = 0 - getHeight(left) ;
}
else if (right != null) {
balanceFactor = getHeight(right) ;
}
else
balanceFactor = 0 ;
return balanceFactor ;
}
private int getHeight(Node p) {
if (p.left == null && p.right == null ) {
return 0 ;
}
else if (p.left != null && p.right != null) {
return 1 + max(p.left.getHeight(), p.right.getHeight());
}
else if (p.left != null) {
return 1 + p.left.getHeight() ;
}
else if (p.right != null) {
return 1 + p.right.getHeight() ;
}
else {
return 0;
}
}
private int max(int x, int y) {
if (x >= y) {
return x;
} else {
return y;
}
}
}
and the function calling the method is:
#Override
public boolean insert(T el) {
boolean test = super.insert(el) ;
if (test) {
return checkBalance(root) ;
}
else
return false ;
}
and the exception I recieve is a repetition of:
Exception in thread "main" java.lang.StackOverflowError
at Node.getHeight(Node.java:54)
at Node.getHeight(Node.java:33)
at Node.getHeight(Node.java:58)
I would suggest that either your tree is deformed or really big. There seems to be no problems with the code.
If your tree is deformed in such a way that you have a Node inserted twice in the same tree then this code will break.
Added - You are eating a little more stack than you need - replacing p.left.getHeight() with getHeight(p.left) etc. would avoid one stack push per recursion. If your issue is merely big tree then this might scrape you through but this would only postpone the problem.
From looking at both getHeight methods, it seems like you don't have a tree but a cyclic graph. You should start testing with a tree consisting of only the root and then add nodes until you observe the infinite recursion. You probably have an error in the function that rebalances the tree.
EDIT: And you should make the attributes (at least left and right) private.
NOTICE: this is homework-related, but I'm not tagging it as such because the 'homework' tag is marked as obselete (?)
Using the following class that implements a binary tree...
class TreeNode
{
private Object value;
private TreeNode left, right;
public TreeNode(Object initValue)
{
value = initValue;
left = null;
right = null;
}
public TreeNode(Object initValue, TreeNode initLeft, TreeNode initRight)
{
value = initValue;
left = initLeft;
right = initRight;
}
public Object getValue()
{
return value;
}
public TreeNode getLeft()
{
return left;
}
public TreeNode getRight()
{
return right;
}
public void setValue(Object theNewValue)
{
value = theNewValue;
}
public void setLeft(TreeNode theNewLeft)
{
left = theNewLeft;
}
public void setRight(TreeNode theNewRight)
{
right = theNewRight;
}
}
I need to calculate the number of nodes in the binary tree that are "only children," this being defined as a node that doesn't have another node stemming from its parent.
This is what I have so far:
public static int countOnlys(TreeNode t)
{
if(t == null)
return 0;
if(isAnOnlyChild(t))
return 1;
return countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
I don't know how to implement the boolean method isAnOnlyChild(TreeNode t)
Could someone please help me?
You are pretty close and have the traversal looking good but in your Treenode you do not have a link between a child and its parent. So You can not tell from say a left child if a sibling (right child) exists.
You could have a parent Treenode (along with left and right) so you could check how many children a given node's parent has. Or as ajp15243 suggested, instead use a method that checks how many children a given node has.
Some pseudo code of the latter:
//we still need to check if that only child has its own children
if hasOnlyChild(t)
return 1 + checkOnlys(left) + checkOnlys(right)
else
return checkOnlys(left) + checkOnlys(right)
As you have already noticed, one solution is to count number of parents that have only one child. This should work:
public static int countOnlys(TreeNode t)
{
if(t == null || numberOfChildren(t)==0){
return 0;
}
if(numberOfChildren(t)==1){
return 1+ countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
if(numberOfChildren(t)==2 ){
return countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
return 0;
}
public static int numberOfChildren (TreeNode t){
int count = 0;
if(t.getLeft() != null ) count++;
if(t.getRight() != null) count++;
return count;
}
A parent has an only child if exactly one of the children is non-null (which implies that exactly one of its children is null):
((t.getLeft() == null || t.getRight() == null)) && !(t.getLeft() == null && t.getRight() == null)
You don't test, however, the node when you visit it as the recursive code traverses the tree. (This is similar to the Visitor pattern.) What you do is test for an only child when you are sitting on the parent. It's actually a logical exclusive-or test because one and only one of the children needs to be non-null to detect that this node has an only child.
So the algorithm is to
visit each node in the tree.
count it, if the node has only one child
That's it. The rest is plumbing.
public static int onlyChild(TreeNode t){
int res = 0;
if( t != null){
// ^ means XOR
if(t.getLeft() == null ^ t.getRight() == null){
res = 1;
}
res += onlyChild(t.getLeft()) + onlyChild(t.getRight()));
}
return res;
}
whenever you traverse a binary tree, think recursively. this should work.
public static int countOnlys(TreeNode t)
{
if(t == null)
return 0;
if (t.getLeft()==null&&t.getRight()==null)
return 1;
return countOnlys(t.getLeft())+countOnlys(t.getRight());
}
public int countNode(Node root) {
if(root == null)
return 0;
if(root.leftChild == null && root.rightChild == null)
return 0;
if(root.leftChild == null || root.rightChild == null)
return 1 + countNode(root.leftChild) + countNode(root.rightChild);
else
return countNode(root.leftChild) + countNode(root.rightChild);
}
So here is the Node class:
public class Node
{
private int _info;
private Node _left;
private Node _right;
public Node()
{
//this._info = Integer.MIN_VALUE;
this._left = null;
this._right = null;
}
public int getInfo()
{
return _info;
}
public void setInfo(int _info)
{
this._info = _info;
}
public Node getLeft()
{
return _left;
}
public void setLeft(Node _left)
{
this._left = _left;
}
public Node getRight()
{
return _right;
}
public void setRight(Node _right)
{
this._right = _right;
}
}
How I create the tree:
public class BalancedBinaryTree
{
private ArrayList<Integer> _numbers;
private Node _root;
public BalancedBinaryTree(ArrayList<Integer> numbers)
{
this._numbers = new ArrayList<>();
this._numbers.addAll(numbers);
Collections.sort(this._numbers);
this._root = new Node();
this.create(this._root, 0, this._numbers.size());
}
private void create(Node tree, int i, int j)
{
if (i < j)
{
int m = i + (j - i) / 2;
tree.setInfo(this._numbers.get(m));
tree.setLeft(new Node());
create(tree.getLeft(), i, m);
tree.setRight(new Node());
create(tree.getRight(), m + 1, j);
}
}
This method computes the depth:
public static int getDepth(Node node)
{
if (node == null)
{
return 0;
}
else
{
int max = 0;
if (getDepth(node.getLeft()) > getDepth(node.getRight()))
{
max = getDepth(node.getLeft());
}
else
{
max = getDepth(node.getRight());
}
return max + 1;
}
}
And these two combined should print the tree by its levels:
public static void printLevel(Node node, int levelToDisplay, int currentLevel)
{
if (node != null)
{
printLevel(node.getLeft(), levelToDisplay, currentLevel);
if (currentLevel == levelToDisplay)
{
System.out.print(node.getInfo() + " ");
}
currentLevel++;
printLevel(node.getRight(), levelToDisplay, currentLevel);
}
}
public static void printLevels(Node node)
{
for (int i = 0; i < getDepth(node); i++)
{
System.out.println("Level :" + i);
printLevel(node, i, 0);
System.out.println();
}
}
In a test class I have:
testNumbers.add(15);
testNumbers.add(20);
testNumbers.add(25);
testNumbers.add(30);
testNumbers.add(35);
testNumbers.add(40);
testNumbers.add(45);
BalancedBinaryTree tree = new BalancedBinaryTree(testNumbers);
BalancedBinaryTree.printLevels(tree.getRoot());
And I get this output:
Level :0
0 15 20 30
Level :1
0 0 25 0 35 40
Level :2
0 0 0 45
Level :3
0
I should get
Level :0
30
Level :1
20 40
Level :2
15 25 35 45
What's wrong with the getDepth method because it seems that it returns 4 levels instead of 3?
Why are there additional nodes? (those zeroes)
I'm pretty sure I solved the problems but I will need an explanation for the following:
This is the modified printlevel method:
public static void printLevel(Node node, int levelToDisplay, int currentLevel)
{
if (node.getLeft() != null && node.getRight() != null)
{
printLevel(node.getLeft(), levelToDisplay, currentLevel+1);
if (currentLevel == levelToDisplay)
{
System.out.print(node.getInfo() + " ");
}
printLevel(node.getRight(), levelToDisplay, currentLevel+1);
}
}
As you can see I test now if the current node has childs instead of checking if the current node exists and this is why those zeroes appeard because the traversal reached the leafs that had no info assigned on their right and left childs.
The thing I want to understand is the difference between incrementing currentLevel and then passing it to the call of printLevel and simply passing currentLevel+1 to the call. Shouldn't it be the same thing ?
And the getDepth function:
public static int getDepth(Node node)
{
if (node.getLeft() == null && node.getRight() == null)
{
return 0;
}
else
{
int max = 0;
if (getDepth(node.getLeft()) > getDepth(node.getRight()))
{
max = getDepth(node.getLeft());
}
else
{
max = getDepth(node.getRight());
}
return 1 + max;
}
}
Same thing here: traversal reached the leafs and got one more call for its childs thus returning one additional level so again, the solution is to test if the current node has childs instead of checking if the current node exits.
What's wrong with the getDepth method because it seems that it returns 4 levels instead of 3?
From your print method it seems, that you number the levels from 0 to n (the root of a tree beeing 0). Your getDepth method however will never return 0.
Two things: if (node != null) this check does not seem to make very much sense. Null does not seem to be an allowed input (as the root is constructed on construction of a Tree). If this is the case (and you do want to check it) an exception might be more appropriate.
The main problem seems to be this: return max + 1;
So the minimal value returned is 0 + 1, which is 1.
As a small sidenote: I would save the values of the two recursive calls of getDepth, it would greatly increase performance.
Also, if you do use short variable names such as i, m or j (in a non-loop index kind of way) it would be helpful to document their meaning.
And conserning your first question:
tree.setLeft(new Node());
What would be the value of this Node as of now? And what will happen if the i < j codition in the recurive call will not pass? If you can answer those questions, you should be able to fix the code yourself.
I have this code:
static int countStu = 0;
public static int countStudent(Node<Student> lst) {
// pre : true
// post : res = number of students in list
if (lst != null) {
countStu++;
countStudent(lst.getNext());
}
return countStu;
}
The problem with this method is I must declare countStu outside the countStudent() method, which is not good in the case when I want to call countStudent() twice, it will make the returned value doubles. How do I solve this problem and able to call countStudent() unlimited times with correct results?
instead, return((lst == null)? 0 : (1 + countStudent(lst.getNext()))).
Change:
if(lst!=null){
countStu++;
countStudent(lst.getNext());
}
return countStu;
to
return lst==null ? 0 : (1+countStudent(lst.getNext()));
Assuming that this is your homework and you really must declare countStu outside (you shouldn't in any normal code), you can simply wrap the value in some class. Add set+get accessors and pass the object as a second argument to the function. Use it then, instead of the global / static variable.
Or simply don't use the variable at all and return the result + 1. Not sure if this is allowed by your rules.
In general when you are trying to do something like is useful to try to remove the explicit state handling somehow.
For example if you have to compute a function f(x) = G(f(x-1)) you can express G as a stateless method and follow the following pattern:
public static ResultType G(ResultType input) {
// compute G stateless
}
public static ResultType F(int x) {
return G(F(x - 1));
}
That way you don't have any side effects like you have with your current code. The downside is usually minor compared with what you are doing right now (the same stack depth is used overall).
The important thing is to make sure the G and F implementations are stateless (not using variables declared outside the method body scope).
Holding the state of the recursion in the static field would not be thread-safe. Instead hold the value in the stack.
I give you both a recursive example which would risk a StackOverflowError with as little as 6k nodes with a default heap as well as a loop version which doesn't suffer from this.
public class SO3765757 {
public static int countNodeRecursive(Node<?> node) {
if(node == null) {
debug("node is null");
return 0;
}
int count = 1 + countNodeRecursive(node.getNext());
debug(count + " = " + node.toString());
return count;
}
public static int countNodeLoop(Node<?> node) {
int count = 0;
for(Node<?> currentNode = node; currentNode != null; currentNode = currentNode.getNext()) {
count += 1;
debug(count + " = " + currentNode.toString());
}
return count;
}
public static void main(String[] args) {
int count = 10;
if(args.length > 0) {
try {
count = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
}
}
Node<Student> node = getNodeTest(count);
System.out.println("Loop count = " + countNodeLoop(node));
try {
System.out.println("Recursive count = " + countNodeRecursive(node));
} catch(StackOverflowError e) {
System.out.println("Recursive count caused " + e.getClass().getName());
}
}
private static void debug(String msg) {
System.out.println("DEBUG:" + msg);
}
private static <T> Node<T> getNodeTest(int count) {
Node<T> prevNode = null;
for(int i=0;i<count;i++) {
Node<T> node;
if(prevNode == null) {
node = new NodeImpl<T>();
} else {
node = new NodeImpl<T>(prevNode);
}
prevNode = node;
}
return prevNode;
}
private static interface Node<T> {
Node<T> getNext();
}
private static class NodeImpl<T> implements Node<T> {
private final Node<T> next;
public NodeImpl() {
this.next = null;
}
public NodeImpl(Node<T> next) {
this.next = next;
}
public Node<T> getNext() {
return next;
}
}
private static interface Student {
}
}
countStudent(lst.getNext());
why do i need to call again this , if lst.getNext() has null. precompute before calling recursion, there are different types.when u call this method countStudent from main method , check the lst value for not null , before recursion starts.
public static int
countStudent(Node lst) {
countStu++;
Node<Student> _tmp;
_tmp = lst.getNext();
if (_tmp != null )
countStudent(lst.getNext());
return countStu; }