When to use return in recursive function? - java

I'm learning the BST recursive construction and found that the insert method does not use return keyword when implementing recursion, but the contains method do use the return key word. Can anybody explain this to me? Many thanks!
static class BST {
public int value;
public BST left;
public BST right;
public BST(int value) {
this.value = value;
}
public BST insert(int value) {
// Write your code here.
// Do not edit the return statement of this method.
if (value < this.value) {
if (left == null) {
BST newBST = new BST(value);
left = newBST;
} else {
left.insert(value);
}
} else {
if (right == null) {
BST newBST = new BST(value);
right = newBST;
} else {
right.insert(value);
}
}
return this;
}
public boolean contains(int value) {
// Write your code here.
if (value < this.value) {
if (left == null) {
return false;
} else {
return left.contains(value);
}
} else if (value > this.value) {
if (right == null) {
return false;
} else {
return right.contains(value);
}
} else{
return true;
}
}

Essentially because insert is not implemented as a function but contains is, meaning that insert just has side effects, it changes the state of BST. Contains is inherently a function - it returns an answer for a given input.
The fact insert returns this at the end is not necessary, it could just as easily have a void return value.
A functional version would return a new BST that is like the original but with the element inserted, and that would require use of the returned value, there would be a bit more complexity there.
(I'm not advocating a functional version here!)

The "insert" function only has a return statement right at the end, because all it has to return is "this", rather than being dependent on outside factors and the execution of the function.
So, short version: You use "return" when you need to, and you do not use "return" when you do not need to.

Related

Insert into BST with recursion in java

New to Java. I learned BST tree insertion before with C++. But I try to replicate its recursive logic with Java like below:
public void tree_insert(Node x, int k) {
if (x == null)
x = new Node(k);
else if (k < x.val)
tree_insert(x.left, k);
else
tree_insert(x.right, k);
}
Suppose I have an empty tree
tree_insert(tree.root, 1);
But the root has not been changed.... I am guessing it may have to to with pass by reference in Java. But I am not exactly sure why it does not work. Some hint? Thanks.
What you are trying to do is assign a Node that has been passed by reference a new value. You already noted this and that is correct (I see that others stated this too).
How you would do this in java is by splitting up the recursion into two steps. EDIT: Not necessarily in java, but helper functions can be a good design to have in mind.
Introduce the insert function which null checks the root.
Private helper method that can generalise the insertion in the tree with recursive calls.
Here is an example:
public boolean insertBST(int value) {
if (root == null) {
root = new Node(value);
return true;
}
return insertBSTHelper(value, root);
}
private boolean insertBSTHelper(int value, Node node) {
if (node.value == value){
return false;
}
if (node.value > value){
if (node.left != null) {
return insertBSTHelper(value, node.left);
} else {
node.left = new Node(value);
return true;
}
} else {
if (node.right != null) {
return insertBSTHelper(value, node.right);
} else {
node.right = new Node(value);
return true;
}
}
}
Since there can only exist distinct elements in a BST, we check for these to ensure that we don't insert the same element twice.
Hope this helps!

how do I create an Instance with this class?

How do I create an instance of this class to test my functions in my main program? I am trying to construct a Binary Search Tree by inserting, removing, and checking if the values are present or not. I am trying to create my object using my constructor. Each time I create an object using my constructor and I pass in the value to my constructor in my main program, I am always getting the value of the constructor which is 9 in this case as my result. I am not surprised by this. But the challenge I am facing is to use the object bst to call function insert (bst.insert()) so that it prints to appropriate result to the screen. Any help is appreciated. Below is the code:
class BST {
static class Algo_BST {
public int value;
public Algo_BST left;
public Algo_BST right;
public Algo_BST(int value) {
this.value = value;
}
public Algo_BST insert(int value) {
// Write your code here.
if(value < this.value){
if(left == null){
Algo_BST bst = new Algo_BST(value);
left = bst;
//this.left = new Algo_BST(value);
}else{
left.insert(value);
}
}else{
if(right == null){
Algo_BST bst = new Algo_BST(value);
right = bst;
//this.right = new Algo_BST(value);
}else{
right.insert(value);
}
}
// Do not edit the return statement of this method.
return this;
}
public boolean contains(int value) {
if (this.value < value){
if(left == null){
return false;
}else{
return left.contains(value);
}
}else if(this.value > value){
if(right == null){
return false;
}else{
return right.contains(value);
}
}else{
return true;
}
}
public String toString() {
return "Data: " + this.value;
}
public static void main(String[] args)
{
BST.Algo_BST bst = new BST.Algo_BST();
System.out.print("Insert: "+bst.insert(90));
System.out.print("Insert: "+bst.insert(50));
System.out.print("Insert: "+bst.insert(70));
System.out.print("Insert: "+bst.insert(80));
System.out.print("Contains: "+bst.contains(80));
System.out.print("Contains: "+bst.contains(1000));
}
}
I tested your class and saw some details:
First. The local property is ok in method insert, you do not need the extra lines:
//Algo_BST bst = new Algo_BST(value);
//left = bst;
this.left = new Algo_BST(value);
...
//Algo_BST bst = new Algo_BST(value);
//right = bst;
this.right = new Algo_BST(value);
Second. Greater than and less than validations are wrong in method contains:
// if (this.value < value){ // Wrong validation
if (this.value > value){
...
// }else if(this.value > value){ // Wrong validation
} else if(this.value < value){
I’ve tested the app with these fixes and it worked well.
These changes to insert make it return the newly-inserted node. I have not tested them.
public Algo_BST insert(int value) {
// Write your code here.
if (value < this.value) {
if (left == null) {
left = new Algo_BST(value);
} else {
left.insert(value)
}
return left;
} else {
if (right == null) {
this.right = new Algo_BST(value);
} else {
right.insert(value);
}
return right;
}
// Do not edit the return statement of this method.
return this;
}
With this change, your 'print' of the result should print what was added. I don't see that is particularly useful since it does not show the tree structure (i.e., you could get that all wrong and the printout would still be correct).
As originally written, this tree allows repeat values. Is that intended?

Binary Tree Search for non key value

I am currently looking for an recursive algorithm to find a non key value in my Tree.
I have my Node Class:
public class TreeNode {
private Person person;
private TreeNode left, right;
public TreeNode(Person person) {
this.person = person;
}
public boolean insert(Person person) {
if (person.getAge() < this.person.getAge()){
if (left != null){
return left.insert(person);
}else {
left = new TreeNode(person);
}
}else{
if (right != null){
return right.insert(person);
}else{
right = new TreeNode(person);
}
}
return true;
}
public boolean countryExists(String country){
if (!this.person.getCountry().equals(country)){
if (right != null) {
return right.countryExists(country);
}
if (left != null) {
return left.countryExists(country);
}
}else {
return true;
}
}
}
The Key value here is the age of a person. I want to find out if there is a Person which comes from a specific country. Therefore I made the function countryExists(String country) I don't know how to implement this and I have searched everywhere and watched a lot of videos about post/pre/inorder. The ordering shouldn't be a problem? I have an issue with returning the correct boolean I think...
Thank you for your help.
In your countryExists method you should return false after two != null checks, because if execution came to this point it means that your node doesn't have left and right siblings (it's a leaf) and it's persons's country doesn't equal to the one you're looking for.
But I would suggest doing some refactoring, and instead of negating this.person.getCountry().equals(country), just use it and return true at the beginning of the method.
public boolean countryExists(String country) {
if (this.person.getCountry().equals(country)) {
return true;
}
if (right != null) {
return right.countryExists(country);
}
if (left != null) {
return left.countryExists(country);
}
return false;
}
Also, this is O(n) solution, because you're not using a key to cut off entire branches, and doing full tree traversal.
To make it O(log n) (in the case when the tree is balanced), you need to use country as key and choose only one branch when searching.

Using a static variable to break out of recursion

Aim: Find if a tree is a balanced binary tree.
I have implemented a program that does work, but wanted to make it more efficient by preventing unnecessary recursion. To do this I am using a static variable, that is set when even a single condition is evaluated to false, so that every other recursive call returns, before making any of their own recursive calls.
static int shouldIExit=0;
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
if(shouldIExit==1 || Math.abs(height(root.left)-height(root.right))>1){
height(root.right))>1: "+ (Math.abs(height(root.left)-height(root.right))>1) ) ;
shouldIExit=1;
return false;
}
else{
return (isBalanced(root.left) && isBalanced(root.right) );
}
}
The problem is that the static variable is somehow being set even when no condition causes it to do so. i.e., shouldIExit is set to 1 even when the if condition corresponding to it, does not evaluate to true.
Is this me not understanding how static variables work?
You don't need a static variable. It's usually bad practice to use non-local variables (either static or instance variables) in a recursive method.
public boolean isBalanced(TreeNode root) {
if(root==null) {
return true;
}
if(Math.abs(height(root.left)-height(root.right))>1) {
return false;
} else{
return (isBalanced(root.left) && isBalanced(root.right) );
}
}
You could save some work if you combine the logic of height and isBalanced. I believe something like this should work:
public boolean isBalanced (TreeNode root) {
return balancedHeight(root) >= 0;
}
public int balancedHeight (TreeNode root) {
if (root == null) {
return 0; // an empty tree is balanced
}
int left = balancedHeight(root.left);
if (left < 0) {
return -1; // left sub-tree is not balanced, so entire tree is not balanced
}
int right = balancedHeight(root.right);
if (left == right) { // the tree is balanced if both sub-trees are balanced
// and both have same height
return left + 1;
} else {
return -1; // tree is not balanced - either the right sub-tree is not
// balanced or the two sub-trees have different heights
}
}

Unusual Java implementation of red/black tree node insertion

I'm writing a program for class in Java regarding red/black trees. I've got a good understanding of how they usually work, and am supposed to use a recursive insertion method. What I would typically use is below, to match my professor's Node class. In regards to color, a 0 is black, a 1 is red. The Node class given to us does not deal with keys at all.
private static void put(int val, int col)
{ root = put(root, val, col); }
private static Node put(Node n, Integer val, int col)
{
if (n == null){
Node t=new Node(val);
t.setColor(1);
return t;
}
int cmp = val.compareTo(n.getValue());
if (cmp < 0) n.setLeft(put(n.getLeft(), val, col));
else if (cmp > 0) n.setRight(put(n.getRight(), val, col));
else n.setColor(col);
if (isRed(n.getRight()) && !isRed(n.getLeft())) n = rotateLeft(n);
if (isRed(n.getLeft()) && isRed(n.getLeft().getLeft())) n = rotateRight(n);
if (isRed(n.getLeft()) && isRed(n.getRight())) flipColors(n);
return n;
}
However, the catch is that we are supposed to return a boolean value--if the user inserts a duplicate value as is already on the tree, we return false and don't attach the node. Otherwise, we attach them and return true; the code given to us for this is below, but is not recursive (part of the project requirements). And while I hadn't implemented a way of balancing or rotating properly, the returned boolean part works.
public boolean insertNode(Node node) {
//Here is just an example of setting colors for a node. So far, it is in green color. But you need to modify the code to dynamically adjust the color to
//either RED or BLACK according to the red-black logic
Node current_node;
// if the root exists
if (root == null) {
root = node; // let the root point to the current node
root.setColor(Node.BLACK);
return true;
} else {
current_node = root;
node.setColor(1);
while (current_node != null) {
int value = current_node.getValue();
if (node.getValue() < value){ // go to the left sub-tree
if (current_node.getLeft() != null) // if the left node is not empty
current_node = current_node.getLeft();
else{ // put node as the left child of current_node
current_node.setLeft(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Left:"+current_node);
}
else if (node.getValue() > value){ // go to the right
if (current_node.getRight() != null) // if the right node is not empty
current_node = current_node.getRight();
else{ // put node as the right child of current_node
current_node.setRight(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Right: "+current_node);
}
else{
//System.out.println("Else: "+current_node);
return false; }
//if(current_node!=null&&current_node.getLeft()!=null&&current_node.getRight()!=null&&current_node.getLeft().isRed()&&current_node.getRight().isRed())
// flipColors(node);
}
}
if(node.getParent()!=null){
node=node.getParent();
System.out.println("Case: node has parent, val="+node.getValue());
}
if(node.getLeft()!=null&&node.getRight()!=null){
if((node.getRight().isRed())&&!node.getLeft().isRed())
node=rotateLeft(node);
if((node.getLeft().isRed())&&(node.getParent()!=null)&&(node.getParent().getLeft().getLeft()!=null)&&(node.getParent().getLeft().getLeft().isRed()))
node=rotateRight(node);
if((node.getLeft().isRed()) && (node.getRight().isRed()))
flipColors(node);
}
return true;
}
I wasn't able to find any comparable implementations online, and it seems that the boolean is necessary for the program's gui to work properly. If someone has a good suggestion for where to start, I would appreciate it!
For the recursive insertNode, I would suggest you the following: Create a function insertNode(Node node, Node current_node) which returns a boolean value. The idea is to always call the function insertNode for the currently investigated node, starting from the root node. If the node cannot be immediately added to current_node, the responsible node is called recursively to handle the node. I have provided you a short example based on your code (with some comments what the basic idea is, there is obviously some stuff missing). I hope, I got your question correctly and this helps you with your understanding.
public boolean insertNode(Node node) {
if (root == null) {
root = node;
root.setColor(Node.BLACK);
return true;
} else {
boolean result = insertNode(node, root);
if (result) {
//Some other important stuff to do...
}
return result;
}
}
public boolean insertNode(Node node, Node current_node) {
int value = current_node.getValue();
if (node.getValue() < value) {
if (current_node.getLeft() != null) {
// Investigate left
return insertNode(node, current_node.getLeft());
} else {
// Insert node left
return true;
}
} else if (node.getValue() > value) {
if (current_node.getRight() != null) {
// Investigate right
return insertNode(node, current_node.getRight());
} else {
// Insert node right
return true;
}
} else {
return false;
}
}
I now have the working functions, as below:
public boolean insertNode(Node node) {
if(root==null){
root=node;
root.setColor(Node.BLACK);
return true;
}
else
node.setColor(Node.RED);
return insertNode(node, root);
}
public boolean insertNode(Node node, Node cur){
if(node.getValue()<cur.getValue()){
if(cur.getLeft()!=null)
return insertNode(node, cur.getLeft());
else{
cur.setLeft(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else if(node.getValue()>cur.getValue()){
if(cur.getRight()!=null)
return insertNode(node, cur.getRight());
else{
cur.setRight(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else
return false;
}

Categories

Resources