I am developing a binary search tree in java. But i am facing certain difficulties in it. Here is the code
class Node {
Node left, right;
Integer data;
Node(Integer d, Node left, Node right) {
this.data = d;
this.left = left;
this.right = right;
}
}
class BinaryTree {
Node root;
public BinaryTree(Node root) {
this.root = root;
}
void insert(int d)
{
if(root==null)
root= new Node(d, null, null);
insert(root,d);
}
void insert(Node root, int d) {
if (root == null) {
root=new Node(d,null,null);
} else if (d > root.data) {
insert(root.right, d);
} else if (d < root.data) {
insert(root.left, d);
}
}
void inorder(Node root) {
if (root != null) {
inorder(root.left);
System.out.println(root.data);
inorder(root.right);
}
}
}
public class BST {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
BinaryTree bt=new BinaryTree(null);
while (!(str = br.readLine()).equalsIgnoreCase("0")) {
bt.insert(Integer.parseInt(str));
}
bt.inorder(bt.root);
}
}
The problem here i am facing is as in java there is only pass by value. I am getting the root as null in every case except the first case in which i have passed the newly created root into it. Here when i am making a recursive call to the insert function by passing the value of either left or right of the root then in the new call the new root has been created if required for it but when the function gets over it's values are not reflected to the caller function's variable.
In short the problem is due to the call by value being followed by the java.
Can anyone please suggest the solution for this problem?
Your calls to insert(root.right/left, d) do not change the original right/left nodes if they are null, but simply make the method arguments point to a new variable (which, as you noticed, in Java won't change the original reference). Your change to the first root works because you call a different method, insert(int).
Have you considered making left and right BinaryTrees instead of Nodes? Also, instead of using "null", consider having an "empty" BinaryTree (with a null root and an isEmpty method).
Note that conceptually, left and right are trees, not nodes, so the design will be cleaner.
Example code. Untested but the idea should be right:
class Node {
BinaryTree left, right;
Integer data;
Node(Integer d, BinaryTree left, BinaryTree right) {
this.data = d;
this.left = left;
this.right = right;
}
}
class BinaryTree {
Node root;
// Empty tree
BinaryTree() {
this(null);
}
BinaryTree(Node root) {
this.root == root;
}
void insert(int d) {
if (this.root == null) {
// The tree was empty, so it creates a new root with empty subtrees
this.root = new Node(d, new BinaryTree(), new BinaryTree());
} else if (d > this.root.data) {
this.root.right.insert(d);
} else if (d < this.root.data) {
this.root.left.insert(d);
}
}
}
Notes:
I respected the style of your existing code.
This implementation will skip repeated elements.
Suggestions,
I wouldn't use an Integer if you mean to use an int value.
If you are reproducing code which is in the JVM already, I would read how the code works there first (and copy what you need)
When I have a bug in my code, I use the debugger to work out what is going wrong.
I start with a the simplest unit I can make which shows the problem, and fixes that simple situation.
I would post the simplest unit test, which anyone can reproduce, and what you see in the debugger here if it doesn't make any sense.
This doesn't really answer your question, but is too long for a comment. ;)
Related
I have seen a lot of implementations of DFS using a boolean variable named visited, which I don't wish to use in my code. While considering a scene where we have a Node class that holds the reference to left and right nodes corresponding to its children and data which can be any Object, can this method be applicable to Binary Trees to calculate dfs ? I have a scenario where I don't have a adjacency list or matrix.
Is the following code a good implementation of DFS ? Is the time complexity of the code O(n) ?
public void dfsForTree(BSTNode root) {
Stack<BSTNode> s = new Stack<BSTNode>();
BSTNode node;
if (root == null) {
return;
}
s.push(root);
while (!s.isEmpty()) {
node = s.pop();
System.out.println(node.getData());
if (node != null) {
if (node.getRight() != null) {
s.push(node.getRight);
}
if (node.getLeft != null) {
s.push(node.getLeft);
}
}
}
}
BSTNode class implementation:
public class BSTNode {
private BSTNode left;
private BSTNode right;
private int data;
/* Constructor */
public BSTNode(int n) {
left = null;
right = null;
data = n;
}
/* Function to set left node */
public void setLeft(BSTNode n) {
left = n;
}
/* Function to set right node */
public void setRight(BSTNode n) {
right = n;
}
/* Function to get left node */
public BSTNode getLeft() {
return left;
}
/* Function to get right node */
public BSTNode getRight() {
return right;
}
/* Function to set data to node */
public void setData(int d) {
data = d;
}
/* Function to get data from node */
public int getData() {
return data;
}
A sure tell of an iterative tree walk is it requires an "up" link on a node (or saves them) to be able to backtrack. You do just this - only saving not "up" links but directly next links to go after backtracking. On the other hand, there are no interdependencies between steps. See Is this function recursive even though it doesn't call itself? for how to distinguish iterative and disguised recursive.
Also see Iterative tree walking for an overview of the algorithms.
Now, for computational complexity. The principle can be found at Big O, how do you calculate/approximate it?.
You do:
process every node
exactly once
push & pop nodes from the stack
each node is also pushed and popped exactly once
So, indeed, it's O(N).
This is my implementation of binary Node class:
public class BinaryNode{
int element;
BinaryNode left;
BinaryNode right;
BinaryNode(int theElement,BinaryNode lt,BinaryNode rt){
element=theElement;
left=lt;
right=rt;
}
BinaryNode(int theElement){
this(theElement,null,null);
}
}
Here's my insert method in binaryTree class
public class BinaryTree {
private BinaryNode root;
public BinaryTree(){
root= null;
}
BinaryTree(int nodeValue){
root=new BinaryNode(nodeValue);
}
public void insert(BinaryNode node,int x){
if(node==null){
node=new BinaryNode(x);
}
else if(node.element<x){
insert(node.left,x);
}
else if (node.element>x){
insert(node.right,x);
}
else
System.out.println("Duplicates not allowed");
}
I have two questions.
1) how can I insert elements to this BinaryTree class and thereby create a tree.
public static void main (String args[]){
BinaryTree t=new BinaryTree();
t.insert(t.root,5);
}
But after inserting 5 how can I call on insert method to add integers like 10,12,78,...
2) Also when I looked up at some code for inserting to binary trees I found this code .
/**
Inserts the given data into the binary tree.
Uses a recursive helper.
*/
public void insert(int data) {
root = insert(root, data);
}
/**
Recursive insert -- given a node pointer, recur down and
insert the given data into the tree. Returns the new
node pointer (the standard way to communicate
a changed pointer back to the caller).
*/
private Node insert(Node node, int data) {
if (node==null) {
node = new Node(data);
}
else {
if (data <= node.data) {
node.left = insert(node.left, data);
}
else {
node.right = insert(node.right, data);
}
}
return(node); // in any case, return the new pointer to the caller
}
The code looks similar to mine, but why use a helper method insert() as well?What's the purpose of it?
Can someone please solve help me to understand this
Inserting an element in a binary tree should require only the tree and the element as input. The tree itself should determine which node should be updated. This is achieved by means of a recursive function which starts from root: this is the helper function, which acts on a node.
The first problem is that you won't be able to access t.root directly because it's private. You either need a getter
public BinaryNode getRoot() {
return this.root;
}
or make root public
The helper method is used, so the new root of the BinaryTree can be determined. And because the root should not be returned to the caller. But since it's easier to insert something into a binary tree recursivley the private method is used to do that.
You would use the methods like this:
public static void main(String[] args) {
BinaryTree t = new BinaryTree(5); //Create a new tree with one item
t.insert(12); // Assuming that you used the implementation with the helper method
t.insert(3); //
t.insert(t.getRoot(),12); // Assuming you used your implementation
t.insert(t.getRoot(),3); //
}
In the following program,
what does this mean left.parent = this; I know it says make parent of left child to be 'this' but what exactly is this. this refers to current instance method right? but can anyone explain a bit better.
public class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode root;
private int size = 0;
public TreeNode(int d) {
data = d;
size = 1;
}
public void setLeftChild(TreeNode left) {
this.left = left;
if (left != null) {
left.root= this;
}
}
Would the same function setLeftChild above be represented like the function below:
void setLeftChild(TreeNode node)
{
if(root == null)
{
this.root = node;
}
else
{
this.left = node;
}
}
Is the implementation correct? first and 2nd?
If not then what is wrong with the 2nd implementation? and vice versa
What is the difference between first and 2nd implementation?
No the bottom code is not correct. In the bottom implementation what you do is you make the left child node actually the parent node of your class. If the node you are in already is not the root node then the left child is set correctly, but the left child does not get its parent set correctly.
The image below is the result of executing the code on the bottom
The image below is the result of executing the top block (which is correct)
Assuming you did
TreeNode a = new TreeNode (1);
At this time a's left, right and root are null
if you did
TreeNode b = new TreeNode (b);
a.setLeftChild (b);
then now a's right and root are still null but left is b
and b's root is now a
this is a reference to current object
http://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html
I would like using my own Node class to implement tree structure in Java. But I'm confused how to do a deep copy to copy a tree.
My Node class would be like this:
public class Node{
private String value;
private Node leftChild;
private Node rightChild;
....
I'm new to recursion, so is there any code I can study? Thank you!
try
class Node {
private String value;
private Node left;
private Node right;
public Node(String value, Node left, Node right) {
this.value = value;
...
}
Node copy() {
Node left = null;
Node right = null;
if (this.left != null) {
left = this.left.copy();
}
if (this.right != null) {
right = this.right.copy();
}
return new Node(value, left, right);
}
}
Doing it recursively using pre-order traversal.
public static Node CopyTheTree(Node root)
{
if (root == null)
{
return null;
}
Node newNode = new Node(null, null, root.Value);
newNode.Left= CopyTheTree(root.Left);
newNode.Right= CopyTheTree(root.Right);
return newNode;
}
You can use something like this. It will go though the old tree depth first wise and create a copy of it.
private Tree getCopyOfTree(oldTree) {
Tree newTree = new Tree();
newTree.setRootNode(new Node());
copy(oldTree.getRootNode(), newTree.getRootNode())
return newTree;
}
private void copy(Node oldNode, Node newNode) {
if (oldNode.getLeftChild != null) {
newNode.setLeftChild(new Node(oldNode.getLeftChild()));
copy(oldNode.getLeftChild, newNode.getLeftChild());
}
if (oldNode.getRightChild != null) {
newNode.setRightChild(new Node(oldNode.getRightChild()));
copy(oldNode.getRightChild, newNode.getRightChild());
}
}
I like Evgeniy Dorofeev's answer above, but sometimes you might not be able to add a method to the type Node as you might not own it. In that case(this is in c#):
public static TreeNode CopyTree(TreeNode originalTreeNode)
{
if (originalTreeNode == null)
{
return null;
}
// copy current node's data
var copiedNode = new TreeNode(originalTreeNode.Data);
// copy current node's children
foreach (var childNode in originalTreeNode.Children)
{
copiedNode.Children.Add(CopyTree(childNode));
}
return copiedNode;
}
Not sure but try something with post order traversal of your tree and creating a new node for each node you traverse. You might require stack for storing the nodes you created to make left and right child links.
public static TreeNode copy( TreeNode source )
{
if( source == null )
return null;
else
return new TreeNode( source.getInfo( ), copy( source.getLeft( ) ), copy( source.getRight( ) ) );
}
/Sure. Sorry for the delay. Anyway... any recursive method has a base case, and one or more recursive cases. In this instance, the first line is obvious... if the argument to the parameter 'source' is null (as it eventually evaluates to in order to end the method's operation), it will return null; if not, the recursive case is initiated. In this case, you're returning the entire copied tree once the recursion is complete.
The 'new' operator is used, indicating the instantiation of a TreeNode with each visit to the various nodes of the tree during the traversal, occurring through recursive calls to 'copy', whose arguments become references to the left and right TreeNodes (if there are any). Once source becomes null in each argument, the base case is initiated, releasing the recursion stack back to the original call to 'copy', which is a copy of the root of the original tree./
Node copy(Node node)
{
if(node==null) return node;
Node node1 =new Node(node.data);
node1.left=copy(node.left);
node1.right=copy(node.right);
return node1;
}
Ok, here is my code. I am trying to practice with Binary Trees. Why can't my size() method access the root node of my binary tree?
Also my root.left, and root.right assignments do not work.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.lang.*;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
System.out.println(bTree.size());
}
}
//Building Binary Trees
class bTree {
static class Node { //remember to initilize a root
String value;
Node left, right;
Node root = new Node("ROOT");
Node lefty = new Node("LEFT0");
Node righty = new Node("RIGHT0");
root.left = lefty;
root.right = righty;
Node(String value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
Node(String value) //THIS IS A SIBLING CONSTRUCTOR
{
this(value, null, null);
}
}
public static int size() //Public | sibling constructor
{
System.out.println("Debug0");
System.out.println(root.value);
return size(root);
}
//This method will find the size of a node
private static int size(Node r) //using recursion
{
if (r == null) {
return 0;
} else {
return 1 + (size(r.left) + size(r.right));
}
}
}
Any help would be much appreciated, I have a final tomorrow on this information!
Sam
As your comment in your code says:
//remember to initialize a root
You didn't do that (at least in your sample).
The only variable root is defined in the sub-class of bTree, and is not directly available to the size() method.
size() should read:
public static int size() {
System.out.println("Debug0");
System.out.println(Node.root.value);
return size(Node.root);
}
root is scoped to your static Node class. size() is outside of that scope, so it can't access root.
Something like this would work:
public class TreeTraversal {
class Node {
String value;
Node left, right;
public Node(String value) {
this.value = value;
}
}
public static void main(String[] args) {
// Construct a binary tree
Node root = new Node("root");
Node child = new Node("child 1");
root.left = child;
child = new Node("child 2");
root.right = child;
// Find its size
System.out.println(size(root));
}
private static int size(Node root) {
return sizeRec(root);
}
private static int sizeRec(Node r) {
if (r == null) {
return 0;
} else {
return 1 + (sizeRec(r.left) + sizeRec(r.right));
}
}
}
This is a sort of condensed version of a binary tree. I have attempted to strip away all unnecessary stuff (nested classes, extra imports, static methods except for main, nested static classes, recursive object construction).
public class Node {
private String value;
private Node left;
private Node right;
public Node(String value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public int size() {
int ret = 1;
if (left != null) ret += left.size();
if (right != null) ret += right.size();
return ret;
}
public static void main(String args[]) {
Node tree = new Node("root",
new Node("left", null, null),
new Node("right", null, null));
// expect 3
System.out.println(tree.size());
}
}
Now, notice a few things:
A tree is just a Node.
size is an instance method of Node. (my recursive structure is a bit different than if it were static, in particular, where the null checks go)
The only members of Node are value, left, and right. I don't actually use value for anything, and without an accessor, would have some difficulty doing so.
My assignment to left and right is in the constructor, not floating freely in the class declaration.
Start with something simple.
From here, you could declare a class BTree (But why? is it just to practice having nested classes?). It would contain a Node named root and a size method that simply calls root's size method.
You could declare a nice constructor that doesn't require children. Then you might also want to provide methods on a Node to set the children after construction.
Relax and focus on the specific problems that are going to be on your final. Find a different practice problem and try again. Eat healthy and get some rest. Then, good luck on your final.
To access root in bTree, you need to write Node.root.
Your Node is a top level class (read up about static inner classes). Hence your code
public static int size() //Public | sibling constructor
{
System.out.println("Debug0");
System.out.println(root.value);
return size(root);
}
won't work, you need to create a root Node.
Furthermore, I think your definition
Node root = new Node("ROOT");
is not necessary in Node, unless you want a reference back to the root node from every node, which I find a bit ugly :-0
Finally, why do you use the class bTree at all? You can identify a Node n with the tree that is rooted at n. I.e. put the size method within node.