Note: I've included the code for the insert in case that is where my error lies.
I'm having trouble removing nodes in my binary search tree. I ran this through eclipse and the node's "pointers" seem to be getting reassigned, but as soon as I exit my recursive method it goes back to the way the node was.
I may be misunderstanding how java is passing the tree nodes between methods.
public abstract class BinaryTree<E> implements Iterable<E> {
protected class Node<T> {
protected Node(T data) {
this.data = data;
}
protected T data;
protected Node<T> left;
protected Node<T> right;
}
public abstract void insert(E data);
public abstract void remove(E data);
public abstract boolean search(E data);
protected Node<E> root;
}
import java.util.Iterator;
public class BinarySearchTree<E extends Comparable<? super E>> extends BinaryTree<E> {
private Node<E> findIOP(Node<E> curr) {
curr = curr.left;
while (curr.right != null) {
curr = curr.right;
}
return curr;
}
public Iterator<E> iterator() {
return null;
}
public static void remove(E data) {
if (root != null){
if (data.compareTo(root.data) == 0) {
if (root.left == null || root.right == null) {
root = root.left != null ? root.left : root.right;
} else {
Node<E> iop = findIOP(root);
E temp = root.data;
root.data = iop.data;
iop.data = temp;
if (root.left == iop) {
root.left = root.left.left;
} else {
Node<E> curr = root.left;
while (curr.right != iop) {
curr = curr.right;
}
curr.right = curr.right.left;
}
}
} else {
if (data.compareTo(root.data) < 0) {
remove(root.left ,data);
} else {
remove(root.right ,data);
}
}
}
}
private void remove (Node<E> node, E data){
if (data.compareTo(node.data) == 0) {
if (node.left == null || node.right == null) {
if (node.left != null) {
// Problem is either here
node = node.left;
} else {
// or here
node = node.right;
}
} else {
Node<E> iop = findIOP(node);
E temp = node.data;
node.data = iop.data;
iop.data = temp;
if (node.left == iop) {
node.left = node.left.left;
} else {
Node<E> curr = node.left;
while (curr.right != iop) {
curr = curr.right;
}
curr.right = curr.right.left;
}
}
} else {
if (data.compareTo(node.data) < 0) {
remove(node.left ,data);
} else {
remove(node.right ,data);
}
}
}
}
When I insert:
tree.insert(10);
tree.insert(15);
tree.insert(6);
tree.insert(8);
tree.insert(9);
and then
tree.remove(8);
System.out.println(tree.root.left.right.data);
is still 8 instead of 9.
Removal works at the root and pointers are properly reassigned if removing from
root.left and root.right.
Any suggestion would be appreciated.
EDIT: I seem to have narrowed down the question. I implemented an iterative version where I make root = curr and change curr.left.right = curr.left.right.right. I notice that this change reflects my root node while when I pass node = root.left.right to my recursive function changing node to node.right does not reflect the changes in the root. Why is this?
Narrowed down some more. Why does node.left = node.left.left make changes to my tree and node = node.left do nothing.
I fixed it by recursively reassigning nodes of the parent as opposed to recursively reassigning the nodes in the child. This is the resulting private and public function.
public void remove(E data) {
Node<E> curr;
if (root != null) {
if (data.compareTo(root.data) == 0) {
if (root.left == null || root.right == null) {
root = root.left != null ? root.left : root.right;
}
else {
Node<E> iop = findIOP(root);
E temp = root.data;
root.data = iop.data;
iop.data = temp;
if (root.left == iop) {
root.left = root.left.left;
}
else {
curr = root.left;
while (curr.right != iop) {
curr = curr.right;
}
curr.right = curr.right.left;
}
}
} else if (data.compareTo(root.data) < 0) {
root.left = remove(data, root.left);
} else {
root.right = remove(data, root.right);
}
}
}
private Node<E> remove(E data, Node<E> node){
Node<E> curr;
if (node != null){
if (data.compareTo(node.data) == 0) {
if (node.left == null || node.right == null) {
node = node.left != null ? node.left : node.right;
return node;
} else {
Node<E> iop = findIOP(node);
E temp = node.data;
node.data = iop.data;
iop.data = temp;
if (node.left == iop) {
node.left = node.left.left;
return node;
} else {
curr = node.left;
while (curr.right != iop) {
curr = curr.right;
}
curr.right = curr.right.left;
return node;
}
}
} else {
if (data.compareTo(node.data) < 0) {
node.left = remove(data, node.left);
if (node.left != null){
return node.left;
}
} else {
node.right = remove(data, node.right);
if (node.right != null){
return node.right;
}
}
// if node.left/right not null
return node;
}
}
// if node = null;
return node;
}
You are indeed right when you say "I may be misunderstanding how java is passing the tree nodes between methods". Consider:
public class Ref {
public static void main(String args[]) {
Integer i = new Integer(4);
passByRef(i);
System.out.println(i); // Prints 4.
}
static void passByRef(Integer j) {
j = new Integer(5);
}
}
Although i is "passed by reference", the reference i itself isn't changed by the method, only the thing that j refers to. Put another way, j is initialized with a copy of the reference i, that is, j initially refers to the same object as i (but crucially is not i). Assigning j to refer to something else has no effect on what i refers to.
To achieve what you want in your search, I suggest you instead return the new reference to the caller. For example, something analogous to the following change:
public class Ref {
public static void main(String args[]) {
Integer i = new Integer(4);
i = passByRef(i);
System.out.println(i); // Prints 5.
}
static Integer passByRef(Integer j) {
j = new Integer(5);
return j;
}
}
Related
public class SearchLinkedList<E> {
private Node<E> first;
public static void main(String[] args){
SearchLinkedList<Integer> list = new SearchLinkedList<Integer>();
list.insert(1000);
list.insert(2000);
list.insert(3000);
System.out.println(list.getFirst());
}
public SearchLinkedList() {
first = null;
}
public void insert(E e) {
if (first == null) {
first = new Node<E>(e);
} else {
//while(temp.next.searched == true) then insert new Node where the next node is null or searched == false
Node<E> temp = new Node<E>(e);
temp.next = first;
first = temp;
}
}
public E getFirst() {
return first.data;
}
public E find(E x) {
if (first == null) {
return null;
} else {
//while (temp != null) if node found set it's searched = true and move it to front of list
Node<E> temp = first;
while (temp != null) {
if (temp.data.equals(x)) {
temp.searched = true;
return temp.data;
}
temp = temp.next;
}
return temp.data;
}
}
private static class Node<E> {
private E data;
private boolean searched;
private Node<E> next;
private Node(E e) {
data = e;
searched = false;
next = null;
}
}
}
So the assignment here is to create a LinkedList class that moves a node to the front of the list (first) if it has been searched.
First image here is when this is called:
list.insert(1000);
list.insert(2000);
list.insert(3000);
Second image is when this is called:
list.find(3000);
list.find(2000);
So the goal is when find is called and node with data is found: Set it's searched boolean to true and move that node to front of list. As of now, my insert just puts new node at the front of list. The comments in insert and find explain what I want to make them do. However, moving an element from the middle of a single linkedlist to front seems hard. Don't know what to do here. You can copy and try this yourself. After calling list.find(2000); and then list.getFirst() We should get 2000. Question is how... My thoughts are on if I should let the Node's booleans decide whether to be infront or not... Not sure here at all.
Thanks to danilllo19 for the help. That answer is correct only issue was that the new elements should be added from the front and so if an element is searched we're supposed to add the new one after the last searched but at the head of the un-serached ones. Solved it like this:
public void insert(E e) {
if(first == null){
first = new Node<E>(e);
}else{
Node<E> temp = first;
while(temp.searched && temp.next != null && temp.next.searched){
temp = temp.next;
}
Node<E> node = new Node<E>(e);
if(temp.searched && temp.next != null && !temp.next.searched){
Node<E> temp2 = temp.next;
temp.next = node;
node.next = temp2;
}else if(temp.searched && temp.next == null){
temp.next = node;
}else{
node.next = temp;
first = node;
}
}
}
I suppose you should do it like this:
public class SearchLinkedList<E> {
private Node<E> first;
public static void main(String[] args) {
SearchLinkedList<Integer> list = new SearchLinkedList<Integer>();
list.insert(1000);
list.insert(2000);
list.insert(3000);
System.out.println(list.getFirst());
System.out.println(list.find(3000));
System.out.println(list.getFirst());
list.insert(4000);
System.out.println(list.find(200));
}
public SearchLinkedList() {
first = null;
}
public void insert(E e) {
if (first == null) {
first = new Node<E>(e);
} else {
//while(temp.next.searched == true) then insert new Node where the next node is null or searched == false
Node<E> temp = first;
while (temp.next != null && temp.next.searched) {
temp = temp.next;
}
Node<E> node = new Node<>(e);
if (temp.next != null) {
node.next = temp.next;
}
temp.next = node;
}
}
public E getFirst() {
return first.data;
}
public E find(E x) {
if (first == null) {
return null;
} else {
//while (temp != null) if node found set it's searched = true and move it to front of list
Node<E> temp = first;
while (temp != null) {
if (temp.data.equals(x)) {
temp.searched = true;
break;
}
temp = temp.next;
}
if (temp == null) return null;
pushForward(temp);
return temp.data;
}
}
//Find pre-linked node with our node, bind our node with parent next node
//and link parent with node.
private void pushForward(Node<E> node) {
if (first == null || first.next == null) return;
Node<E> temp = first;
while (temp.next != null) {
if (temp.next.equals(node)) {
temp.next = temp.next.next;
node.next = first;
first = node;
break;
}
temp = temp.next;
}
}
private static class Node<E> {
private E data;
private boolean searched;
private Node<E> next;
private Node(E e) {
data = e;
searched = false;
next = null;
}
}
}
Also you could mix pushForward and find methods to make find to do what you want by one iteration through the list (O(n)), because O(n^2) there.
Might be helpful: https://www.geeksforgeeks.org/java-program-for-inserting-node-in-the-middle-of-the-linked-list/
Why am I getting false while doing search(7)?
I tried recursive solution its working fine..
tried implementing with loop failed
public class BST {
class Node {
int data;
Node left , right;
public Node(int data) {
this.data = data;
this.left = this.right = null;
}
}
Node root;
public BST() {
this.root = null;
}
public void insert(int data) {
// create a new node and start iteration from root node
Node newNode = new Node(data);
Node currentNode = this.root;
while (true) {
if (currentNode == null) {
currentNode = newNode;
break;
}
if (data < currentNode.data) { // if data is less go left
currentNode = currentNode.left;
} else if (data > currentNode.data) { // if data is greater go right
currentNode = currentNode.right;
} else { // do nothing for duplicates
break;
}
}
}
public boolean search(int data) {
Node currentNode = this.root;
while (true) {
if (currentNode == null) {
return false;
}
if (data == currentNode.data) {
return true;
} else if (data < currentNode.data) {
currentNode = currentNode.left;
} else {
currentNode = currentNode.right;
}
}
}
public static void main(String... args) {
BST tree = new BST();
tree.insert(15);
tree.insert(7);
System.out.println(tree.search(7));
}
}
Problem is inside the insert method - you are not inserting the nodes correctly inside the tree.
If the tree is empty, you should assign to this.root, not currentNode. Assigning to currentNode has no affect on this.root.
Currently, your code isn't inserting any node inside the tree; it simply assigns the new node to the local variable of insert method, i.e. currentNode.
If the condition data < currentNode.data is true, then you need to check if the currentNode.left is null or not. If it is, then link the new node with the current node as shown below:
currentNode.left = newNode;
If currentNode.left is not null, then do the following:
currentNode = currentNode.left;
Currently, your code moves the currentNode to null and then assigns the newNode to the currentNode without a reference to its parent node in the tree.
Do step 2 for data > currentNode.data as well.
Change the implementation of the insert method as shown below:
public void insert(int data) {
Node newNode = new Node(data);
if (this.root == null) {
this.root = newNode;
return;
}
Node currentNode = this.root;
while (true) {
if (data < currentNode.data) {
if (currentNode.left == null) {
currentNode.left = newNode;
} else {
currentNode = currentNode.left;
}
} else if (data > currentNode.data) {
if (currentNode.right == null) {
currentNode.right = newNode;
} else {
currentNode = currentNode.right;
}
} else {
break;
}
}
}
I'm having trouble implementing an AVL tree in java and would appreciate your help,
preferably by explaining what's wrong with my code (I've seen different implementations and would like to figure out what's wrong with mine).
public class AVLTree<T> {
public AVLNode<T> root;
int size;
//constructor
public AVLTree() {
root = null;
size = 0;
}
public void add(T obj) {
//initialize the new node
AVLNode<T> node = new AVLNode<T>(obj);
//if the tree is empty than our new node will serve as a root
if(root == null)
{
root = node;
size++;
return;
}
add(root, node);
}
private void checkViolations(AVLNode<T> node) {
int dif = Math.abs(height(node.left) - height(node.right)) ;
//there's a violation at our level
if(dif > 1)
{
rebalance(node);
}
//if we're at the root, tree is balances(AVL)
if(node.parent == null) return;
//we're not at the top, check parent
checkViolations(node.parent);
}
private void rebalance(AVLNode<T> node) {
//right subtree is bigger than left subtree
if(height(node.right) - height(node.left) > 1)
{
//problem is right-right
if(height(node.right.right) > height(node.right.left))
node = leftRotation(node);
//problem is right-left
else
node = rightLeftRotation(node);
}
//left subtree is bigger than right subtree
else
{
//problem is left-left
if (height(node.left.left) > height(node.left.right))
node = rightRotation(node);
//problem is left-right
else
node = leftRightRotation(node);
}
if (node.parent == null)
root = node;
}
private AVLNode<T> rightLeftRotation(AVLNode<T> node) {
node.right = rightRotation(node.right);
return leftRotation(node);
}
private AVLNode<T> leftRightRotation(AVLNode<T> node){
node.left = leftRotation(node.left);
return rightRotation(node);
}
private AVLNode<T> rightRotation(AVLNode<T> node) {
AVLNode<T> temp = node.left;
node.left = temp.right;
temp.parent = node.parent;
temp.right = node;
node.parent = temp;
return temp;
}
private AVLNode<T> leftRotation(AVLNode<T> node) {
AVLNode<T> temp = node.right;
node.right = temp.left;
temp.parent = node.parent;
temp.left = node;
node.parent = temp;
return temp;
}
private int height(AVLNode<T> node) {
//base case
if(node == null) return 0;
return 1 + (Math.max(height(node.left), height(node.right)));
}
private void add(AVLNode<T> parent, AVLNode<T> newNode) {
if(((Comparable<T>)newNode.data).compareTo(parent.data) > 0)
{
if(parent.right == null)
{
parent.right = newNode;
newNode.parent = parent;
size++;
}
else add(parent.right, newNode);
}
else
{
if(parent.left == null)
{
parent.left = newNode;
newNode.parent = parent;
size++;
}
else add(parent.left, newNode);
}
checkViolations(newNode);
}
}
I'm trying to add the next numbers in this order (left to right): 1,2,3,4,5
up until 4, everything seems to go great.
Thank you
I have written a Code for AVL Tree Insertion but when I try to print the value of Root Node it always returns Null. I am unable to understand the reason.Anyone who can solve this problem? I have tried many times but I could not resolve the problem. I am confused. I hope that someone from here will help in the case of resolving the problem I have as I am sure there are high level of experts here.
public class AVLTreeMethods {
public Node root = null;
public int height(Node node){
if (node == null)
return 0;
return node.height;
}
public int max(Node node1, Node node2){
if (node1.height > node2.height)
return node1.height;
return node2.height;
}
public Node rotateRight(Node node){
Node newNode = node.left;
node.left = newNode.right;
newNode.right = node;
node.height = max(node.left,node.right) + 1;
newNode.height = max(newNode.left, newNode.right) + 1;
return newNode;
}
public Node rotateleft(Node node){
Node newNode = node.right;
node.right = newNode.left;
newNode.left = node;
node.height = max(node.left,node.right) + 1;
newNode.height = max(newNode.left, newNode.right) + 1;
return newNode;
}
public Node AVLINSERT(int data, Node root){
if (root == null){
return new Node(data);
}
else if (data > root.data){
root.left = AVLINSERT(data, root.left);
}
else if (data < root.data){
root.right = AVLINSERT(data, root.right);
}
int balance = height(root.left) - height(root.right);
if (balance > 1){
if (height(root.left.left) > height(root.left.right)){
return rotateRight(root);
}
else {
root.left = rotateleft(root.left);
return rotateRight(root);
}
}
if (balance < -1){
if (height(root.right.right) > height(root.right.left)){
return rotateleft(root);
}
else
root.right = rotateRight(root);
return rotateleft(root);
}
root.height = 1 + max(root.left, root.right);
return root;
}
public void inorderPrinting(Node root){
inorderPrinting(root.left);
System.out.println(root.data);
inorderPrinting(root.right);
}
public void callingAVLInserting(int data){
AVLINSERT(data,root);
}
public void callinInorderPrinting(){
inorderPrinting(root);
}
}
Just by looking at your code, you have initialised the root to null however, you do not have any constructor that initializes it.
So try add something of the sort.
public class AVLTreeMethods {
public Node root = null;
//add the following
public AVLTreeMethods() {
//initialize your root appropriately e.g.
this.root = new Node(//pass in some data e.g 0)
}
...rest of your code
}
I have written the following pseudocode for a removeNode() method while working with BST's:
If left is null
Replace n with n.right
Else if n.right is null
Replace n with n.left
Else
Find Predecessor of n
Copy data from predecessor to n
Recursively delete predecessor*
Not only do I want this method to delete or remove Nodes, but I also want it to return true if the deletion is successful.
This is what I have written so far, and I was wondering if anyone would have feedback, suggested changes, or tips to help me complete the method. I will also attach my whole program below this method.
private void removeNode(Node<E> n) {
if (n.left == null) {
replace(n, n.right);
} else if (n.right == null) {
replace(n, n.left);
} else {
//How do I find pred of n
//Copy data from pred to n
//Recursively delete pred
}
}
Here is the rest of my code:
import java.util.Random;
public class BinarySearchTree<E extends Comparable<? super E>> extends BinaryTree<E> {
public boolean contains(E item) {
return findNode(item, root) != null;
}
private Node<E> findNode(E item, Node<E> n) {
if (n == null || item == null) return null;
int result = item.compareTo(n.data);
if (result == 0) {
return n;
} else if (result > 0) {
return findNode(item, n.right);
} else {
return findNode(item, n.left);
}
}
public E max() {
Node<E> m = maxNode(root);
return (m != null) ? m.data : null;
}
private Node<E> maxNode(Node<E> n) {
if (n == null) return null;
if (n.right == null) return n;
return maxNode(n.right);
}
public E min() {
Node<E> m = minNode(root);
return (m != null) ? m.data : null;
}
private Node<E> minNode(Node<E> n) {
if (n == null) return null;
if (n.left == null) return n;
return minNode(n.left);
}
public E pred(E item) {
Node<E> n = findNode(item, root);
if (n == null) return null;
Node<E> pred = predNode(n);
return (pred != null) ? pred.data : null;
}
private Node<E> predNode(Node<E> n) {
assert n != null;
if (n.left != null) return maxNode(n.left);
Node<E> p = n.parent;
while (p != null && p.left == n) {
n = p;
p = p.parent;
}
return p;
}
public E succ(E item) {
Node<E> n = findNode(item, root);
if (n == null) return null;
Node<E> succ = succNode(n);
return (succ != null) ? succ.data : null;
}
private Node<E> succNode(Node<E> n) {
assert n != null;
if (n.right != null) return minNode(n.right);
Node<E> p = n.parent;
while (p != null && p.right == n) {
n = p;
p = p.parent;
}
return p;
}
public void add(E item) {
if (item == null) return;
if (root == null) {
root = new Node<>(item, null);
} else {
addNode(item, root);
}
}
private void addNode(E item, Node<E> n) {
assert item != null && n != null;
int result = item.compareTo(n.data);
if (result < 0) {
if (n.left == null) {
n.left = new Node<>(item, n);
} else {
addNode(item, n.left);
}
} else if (result > 0) {
if (n.right == null) {
n.right = new Node<>(item, n);
} else {
addNode(item, n.right);
}
} else {
return; // do not add duplicates
}
}
public boolean remove(E item) {
Node<E> n = findNode(item, root);
if (n == null) return false;
removeNode(n);
return true;
}
private void removeNode(Node<E> n) {
if (n.left == null) {
replace(n, n.right);
} else if (n.right == null) {
replace(n, n.left);
} else {
//How do I find pred of n
//Copy data from pred to n
//Recursively delete pred
}
}
private void replace(Node<E> n, Node<E> child) {
assert n != null;
Node<E> parent = n.parent;
if (parent == null) {
root = child;
} else if (parent.left == n) {
parent.left = child;
} else {
parent.right = child;
}
if (child != null) child.parent = parent;
}
public String toString() {
return inorder();
}
The code to remove an element is very straightforward.
Search for the node you want to remove.
Check if the node has children.
Case 1 - Has Only left child -> Replace current node with left child.
Case 2 - Has Only right child -> Replace current node with right child.
Case 3 - Has both children -> Find smallest element in right child subtree, replace current node with that node and then delete that node.
The Code can be implemented recursively as follows ->
BinarySearchTree.prototype.remove = function(data) {
var that = this;
var remove = function(node,data){
if(node.data === data){
if(!node.left && !node.right){
return null;
}
if(!node.left){
return node.right;
}
if(!node.right){
return node.left;
}
//2 children
var temp = that.findMin(node.right);
node.data = temp;
node.right = remove(node.right,temp);
}else if(data < node.data){
node.left = remove(node.left,data);
return node;
}else{
node.right = remove(node.right,data);
return node;
}
};
this.root = remove(this.root,data);
};