Binary search tree deletion method error - java

I am trying to write a method which recursively deletes a node from a binary search tree. I understand the algorithm, but my code is currently returning an error. When I try to delete a leaf node, i.e. a node which has no children, it deletes that node but also the topmost node of the tree.
I already have methods which to find the head of a node, getValue(), as well as finding the left and right subtrees, getLeft() and getRight(). I also have the method isEmpty() which checks to see if a tree is empty.
This is my code currently, where x is the node to be deleted and a is a binary search tree:
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return delete(x, a.getRight());
} else if (x<a.getValue()) {
return delete(x, a.getLeft());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return delete(x, a.getLeft());
} if (a.getLeft().isEmpty()) {
return delete(x, a.getRight());
} else {
return new Tree(); //not yet completed
}
}
}
Can anyone give me any clues as to why this would be happening? Thanks in advance
Edit: Here is the code which eventually worked if anyone happens to stumble across this question
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return new Tree(a.getValue(), a.getLeft(), delete(x, a.getRight()));
} else if (x<a.getValue()) {
return new Tree(a.getValue(), delete(x, a.getLeft()), a.getRight());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return new Tree(a.getLeft().getValue(), delete(a.getLeft().getValue(), a.getLeft()), a.getRight());
} if (a.getLeft().isEmpty()) {
return new Tree(a.getRight().getValue(), a.getLeft(), delete(a.getRight().getValue(), a.getRight()));
} else {
return new Tree(max(a.getLeft()), delete(max(a.getLeft()), a.getLeft()), a.getRight());
}
}
}

This method returns an empty tree instead of setting left or right as empty. This is why you think it's deleting the top node. Also it doesn't look like it handles deleting the node itself, only child nodes.

You never actually delete anything. There are two ways to do this.
Making a structureal copy of the tree until the node to be deleted and then take one of the children and insert the other to the chosen child the result of the insert is the result of the tree.
Finding the parent of the node to be deleted and mutate the accessor to the node to be one of the children and then add the other child subtree to the parent tree. Basically here you have a tree class that handles insertion and which has a root. Deleting the root is a special case with rebinding instead of altering a node.
If you are making a backtracking algorithm where going back to a previous tree is needed #1 is the only choice and it will share as much structure with the previous version of the tree. If you want to iterate and update a data structure to reflect something where you never need th eprevious state #2 is the best choice.

Related

Compilation error while implementing the Depth first search Recursively

I am new to using recursion for my methods. I tend to steer away from them for quite a few reasons. However, for a project, it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph.
Since I am not too well versed in recursion, I don't understand why I am getting the following error.
This method must return a result of type LinkedList.Node
The code I have currently is:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
DFSTime(node.nextNode);
}
}
It is unfinished code since I still need to implement some logic, however, I don't understand how to eliminate the error. Is there something very basic that I am missing?
The reason of the compilation error is pretty trivial. The compiler clearly tells that didn't provide the result to return for all possible cases.
The more important is that your current approach is not correct.
it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph
There are crucial things to consider:
Field nextNode is very suspicious. If each Node holds a reference pointing to a single node only, in fact the data structure you've created by definition isn't a Graph, but a Singly linked list. And doesn't make sense to implement DFS for a list. Every node should point to a collection of nodes, no to a single node.
You have to distinguish somehow between unvisited nodes and nodes that are already visited. Or else you might and up with infinite recursion. For that, you can define a boolean field isVisited inside the Node, or place every visited node into a HashSet.
Since you've chosen to create a recursive implementation of DFS, you don't need to create a stack. It's required only for iterative implementation.
Don't overuse global variables. I guess you might want to be able to check whether it is possible to reach different airports of destination without reinstantiating the graph.
Use getters and setters instead of accessing fields directly. It's a preferred practice in Java.
Your method might look like this (it's not necessary that element should be of type String it's just an illustration of the overall idea):
public Node DFSTime(Node node, String destinationAirport){
if(node == null || node.isVisited()) {
return null;
}
if (node.getElement().equals(destinationAirport)) {
System.out.println("The destination airport was found");
return node;
}
node.setVisited(true);
for (Node neighbour: node.getNeighbours()) {
Node result = DFSTime(neighbour, destinationAirport);
if (result != null) return result;
}
return null;
}
And the node might look like this:
public class Node {
private String element;
private List<Node> neighbours;
private boolean isVisited;
public Node(String element, List<Node> neighbours) {
this.element = element;
this.neighbours = neighbours;
}
public void setVisited(boolean visited) {
isVisited = visited;
}
public boolean isVisited() {
return isVisited;
}
public void addNeighbours(Node neighbour) {
neighbours.add(neighbour);
}
public String getElement() {
return element;
}
public List<Node> getNeighbours() {
return neighbours;
}
}
You should have a default return statement at the end of the function after the closing of the else.
In methods conditional blocks (if-else), you need to make sure you are returning appropriate Type from all conditional statements, so that there is no compile-time error. In your case, else block is recursively calling DFSTime(..) without returning anything.
You might want to return reference which gets called via recursive call, something like below:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
Node node = DFSTime(node.nextNode);
return node;
}
}

binary tree insertion using recursion (clarification)

I have the following code to insert into the binary tree:
public void insert(T item) {
root = insert(item, root);
}
private Node insert(T item, Node node) {
if(node == null){
return new Node(item, null, null);
} else {
if(item.compareTo(node.item) > 0) {
node.rightChild = insert(item, node.rightChild);
} else {
node.leftChild = insert(item, node.leftChild);
}
}
return node;
}
the code works fine, I have tested it
my question is, how come the root is never changed since in the public function I assigned the returned node from the private function to the root
Thank you!
The public insert is just an interface into the recursive method which rebuilds the tree as the stack unwinds ending where you started, at the root (root = ...). Except for the first insert, you go left or right until you insert at the leaf level. Without any balancing, you will have the same root (assuming no removals) for the lifetime of the tree. Therefore, the only time the root changes on insert is when it's empty.
Note: There's also a matter of what happens when a node is inserted with an existing value; do you discard it, allow duplicates, or swap the objects? That's an implementation detail.
I read your code again and your code is correct. The return value is always the root element because your frist function call is insert(item, root) and the return value is what you give.

How memory-efficient is Binary Tree implementation in Java?

So I just wrote code for insertion of nodes in binary tree (NOT BST).
I noticed that every time the recursive insert returns a 'node', it is assigned to the initial node.
Does this mean, that the memory reference of root of this tree would change on the completion of each insert?
public void add(int data)
{
root=add(root,data);
}
public static BinaryNode add(BinaryNode node, int data) {
if(node==null)
{
node=new BinaryNode(data);
}
else {
///IF not 1st element, flow enters this part
if(node.left==null && node.right==null)
{
node.left=add(node.right,data);
}
else if (node.right == null) {
node.right=add(node.right, data);
} else {
node.left=add(node.left, data);
}
}
return node;
}
Within add the only time you change node is if the tree at that point is empty, so the answer is no except for the first insert.
However, note that you add a new level to the tree only on the left (first if condition) so the "tree" you build is highly unbalanced to the left. This isn't really a "tree", it's more like a strange linked list. Also, since you don't maintain any particular sequence it can't be better than a simple unordered list for searches.

Adding an element a binary search tree

Trying to add an element to BST. I have an idea of how to do it, but my implementation is destructive, and the original root is not preserved (so the tree basically becomes useless). The tree is based on lists, and this method is based on recursion. My real problem is preserving the original root. I'm using generics.
So far what I have:
public void addElement(E elem, Node<E> root) {
Create node with a value of elem, call it newNode
Case 1: Tree is empty
root = newNode();
return; //End of method.
Otherwise, keep searching the tree (by comparing the value of out node a with the root of the tree.
if (!root.hasLeft() && !root.hasRight) { //if the root in question has no children
if (elem < rootValue) { //Set the element as the left element
root.setLeft(newNode);
}
else { //Set the element as the right element.
root.setRight(newNode);
}
}
else {
if (E < root.getElem()) {
//This is where the value of our node is compared to the value of the root, which we passed in.
//(I know that we can't use the < and > operators with generics, but assume it works).
root = root.getLeft() //Left node is new root
addElement(elem, root); //Call the method again
}
else {
root = root.getRight(); //Right node is new root
addElement(elem, root) //Call method again
}
}
}
Forgive me if this is a duplicate/vague question, this is my first post on SO, and I'm kind of noob.
if (!root.hasLeft() && !root.hasRight) {
This logic is wrong. You're only considering "setting" the left child, if you have neither a left nor right child. This change should do it:
void addElement(elem, root)
{
if (elem < root.value) {
if(!root.hasLeft())
root.setLeft(newNode);
else
addElement(elem, root.getLeft());
}
else {
if(!root.hasRight())
root.setRight(newNode);
else
addElement(elem, root.getRight());
}
}
You should not be changing root of the class, just passing it into the next method call. This should preserve root.
By the way, I assume you have rootValue = root.value somewhere or somethign similar?

Changing the recursive insertion of the (binary Search tree) to non-recursive?

I am trying to change my recursive insert method of the BST into non-recursive( maybe While loop)
The reason for this changing because I want to see if it is possible.
Here is the code of insertion:
public void insert(String value)
{
//The node is stored in the root
root = insert(value,root);
}
private Character insert(String value,Character current)
{
if(current == null)
{
//Add the root if the tree empty
current = new Character(value);
}
else
//If the value that we want to insert < root value, then keep going to left till
//it's empty then inserted at left end. Done by recursion
if(value.compareTo(current.getElement())<=-1)
{
current.setLeft(insert(value,current.getLeft()));
}
else
//If the value that we want to insert > root value, then keep going to right till
//it's empty then inserted at right end. Done by recursion
if(value.compareTo(current.getElement())>=1)
{
current.setRight(insert(value,current.getRight()));
}
else
{
//Else, the number we want to insert in already in the tree
System.out.println("Duplicate numbers inserted" + current.getElement());
}
//returning the node tree so that we store it in the root
return current;
}
Could I change this code into non recursive ?
Cheers
Yes, but you need to alter the data structure a little bit to make it works.
The node has to know its left child and right child.
The algorithm looks like this:
current = root;
while(current != null){
if(value.compareTo(current.getElement())<=-1)
{
current = current.left_child;
}else if(value.compareTo(current.getElement())>=1){
current = current.right_child;
}else{
// Duplication
}
}
Actually there are some good examples before, you may want to check those out first:
Write a non-recursive traversal of a Binary Search Tree using constant space and O(n) run time
Nonrecursive/Iterative Binary Search Tree in C (Homework)
Yes, you could define your insert function non-recursively.
However, to do this, your insert function will have to define in-order traversal iterator for BST, which is recursively defined.
I believe there is a way to define in-order traversal non-recursively, but depending on implementation this can be very inefficient.
BST itself is basically recursively defined, and it is always efficient to define your insert function recursively. (I could write some pseudo-code if you really need it, but I think it is kind of meaningless and I do not know about the implementation detail of your in-order traversal iterator)
Please don't forget to select this as an answer :-)
Insert using while loop
public Node insert(Node root,int n) {
while (true) {
if (root.data>n) {
if (root.left==null) {
root.left= new Node(n);
return (root.left);
}
root=root.left;
}
else if (root.data<n) {
if (root.right == null) {
root.right= new Node(n);
}
}
}
}

Categories

Resources