Finding Inorder Successor in Binary Search Tree [duplicate] - java

This question already has answers here:
In Order Successor in Binary Search Tree
(19 answers)
Closed 5 years ago.
I'm creating Binary Search Tree class I got all my functions working accept the Successor.
My tree input is
30 10 45 38 20 50 25 33 8 12
When I print Inorder traversal it come up as
8 10 12 20 25 30 33 38 45 50
When I enter value 8 its says its successor is 12. Same for input 10 and 12 itself.
When I enter value 33 it says successor is 50. Which its not.
I can't seem to fix it. Any help of suggestion will be appreciated.
I'm calling it in main like:
BinarySearchTree BST = new BinarySearchTree(array);
BST.getSeccessor(a); // where a is user input to find it successor
Following is my code...
public TreeNode Successor(TreeNode node) {
if (node == null)
return node;
if (node.right != null) {
return leftMostNode(node.right);
}
TreeNode y = node.parent;
while (null != y && (y.right).equals(node)) {
node = y;
y = y.parent;
}
return y;
}
public static TreeNode leftMostNode(TreeNode node) {
if (null == node) { return null; }
while (null != node.left) {
node = node.left;
}
return node;
}
/** Search value in Tree need for Successor **/
public TreeNode Search(int key) {
TreeNode node = root;
while (node != null) {
if (key < node.value) {
node = node.left;
} else if (key > node.value) {
node = node.right;
}
return node;
}
return null;
}
/** Returns Successor of given value **/
public int getSuccessor(int val) {
TreeNode node = Successor(Search(val));
return node.value;
}

I added working solution based on pseudo-code in Niklas answer :
public TreeNode successor(TreeNode node) {
if (node == null)
return node;
if (node.right != null) {
return leftMostNode(node.right);
}
while (null != node.parent /*while we are not root*/
&& node.parent.right == node) /* and while we are "right" node */ {
node = node.parent; // go one level up
}
return node.parent;
}
For this to work, you have to fix implementation of some of your methods (provided below) :
/** Search value in Tree need for Successor **/
public TreeNode search(int key) {
TreeNode node = root;
while (node != null
&& key != node.value) {
if(key < node.value) {
node = node.left;
} else if (key > node.value) {
node = node.right;
}
}
return node;
}
/** Returns Successor of given value **/
public int getSuccessor(int val) {
TreeNode node;
if (null == (node = search(val))
|| (null == (node = successor(node))) {
// either val is not in BST, or it is the last value-> no successor
return ERROR_CODE; // -1, for instance;
}
return node.value;
}

A possible algorithm would be the following:
If you have a non-empty right subtree, the successor is the smallest value in that subtree
Otherwise, walk up the tree unless you are no longer the right child of your parent or until you reach the root
If you are at the root now, you have no successor. Otherwise, walk up one more step and you are at the successor
Example:
if node.right != null
return leftmostInSubtree(node.right)
while node != root && node.parent.right == node
node = node.parent
if node == root
return null
return node.parent

The inorder successor is going to be
if (node.hasRight())
node = node.getRight();
else {
while (node.isRightChild())
node = node.getParent();
return node.getParent();
}
while (node.hasLeft())
node = node.getLeft();
return node;
Might be a good idea to put some null checks in there, too.

I think the above code won't work for the rightmost last node.
Here is the improved version:
if(node.right!=null)
{
node=node.right;
while(node.left!=null)
node=node.left;
}`
else if(node.parent==root)
return null;
else if(node==node.parent.left)
node=node.parent;
else
{
while(node.parent!=null)
node=node.parent
}
return node;

Related

Does not remove last item in Boolean remove(object o) method

This removes almost all of what is supposed to, except for the last item.
This is what I get back when I submit it:
Input: [thing, word, stuff, and, both, zoo, yes]
----------Expected size: 0 BST actual number of nodes: 1
Invalid tree after removing thing
Code Below:
#SuppressWarnings("unchecked")
public boolean remove(Object o) {
Node n = root;
while (n != null) {
int comp = n.value.compareTo(o);
if (comp == 0) {
size--;
remove(n);
return true;
} else if (comp > 0) {
n = n.left;
} else {
n = n.right;
}
}
return false;
}
private void remove(Node root) {
if (root.left == null && root.right == null) {
if (root.parent == null) {
root = null;
} else {
if (root.parent.left == root) {
root.parent.left = null;
} else {
root.parent.right = null;
}
}
} else if (root.left == null || root.right == null) {
Node child = root.left;
if (root.left == null) {
child = root.right;
}
if (root.parent == null) {
root = child;
} else if (root.parent.left == root) {
root.parent.left = child;
} else {
root.parent.right = child;
}
child.parent = root.parent;
} else {
Node successor = root.right;
if (successor.left == null) {
root.value = successor.value;
root.right = successor.right;
if (successor.right != null) {
successor.right.parent = root;
}
} else {
while (successor.left != null) {
successor = successor.left;
}
root.value = successor.value;
successor.parent.left = successor.right;
if (successor.right != null) {
successor.right.parent = successor.parent;
}
}
}
}
Removal of a node in a Binary-search-tree consists of the following steps:
Find the node
You need to make sure that you have a function which is used for searching in order to find the node to be removed.
Handle the node's subtree
If the node has less than two children, then the subtree can be trivially changed. If there is a child, then the current node will be replaced by its child. Otherwise, if there are two children of the node to be removed, then you will just need to replace the node to be removed with the rightmost node of the left subtree or the leftmost node of the right subtree of the element to be removed.
Ensure that if you have replaced your current node with something else, then the other node will not exist as a duplicate.
In order to achieve this you will need methods like:
- search
- find leftmost/rightmost node of subtree
- remove
Your current code is over-complicated. I would rewrite it using atomic methods.

How to delete a node that has been found

I'm working on a binary search tree where i have to delete a node. The node has already been found, so i don't need to traverse and find the specific node. All i need is to delete a node, which is taken as an arguement.
I have started the the node remove method and currently only done how to delete a node if it has no children or is a leaf node. How do i implement a java code which will delete if it has 1 children or a parent?
my current remove method:
public void removeHelper(Node focus){
if(focus.leftChild == null && focus.rightChild == null){
focus = null;
}
// if the node has 1 child
// if the node has 2 children
}
You need to travel down the tree, because you will need to replace the root field, or either the leftChild or rightChild of the parent node.
To remove a node that has both leftChild and rightChild not null, you can replace the node with either the rightmost node of the left subtree, or the leftmost node of the right subtree.
In this example, I assume that the methods are in a class (Tree?) that have a Node field called root, and that the Nodes have a field value that is a Comparable:
public void remove(Node focus) {
root = removeHelper(root, focus);
}
public static Node removeHelper(Node root, Node focus) {
if (root == null) {
return null;
} else if (root == focus) {
if (focus.leftChild == null) {
return focus.rightChild;
} else if (focus.rightChild == null) {
return focus.leftChild;
} else {
Node node = removeLeftMostOfRight(focus);
node.leftChild = focus.leftChild;
node.rightChild = focus.rightChild;
return node;
}
} else {
int r = focus.value.compareTo(root.value);
if (r < 0) {
root.leftChild = removeHelper(root.leftChild, focus);
} else {
root.rightChild = removeHelper(root.rightChild, focus);
}
return root;
}
}
private static Node removeLeftMostOfRight(Node focus) {
Node node = focus.rightChild;
if (node.leftChild == null) {
focus.rightChild = node.rightChild;
} else {
Node prev;
do {
prev = node;
node = node.leftChild;
} while (node.leftChild != null);
prev.leftChild = node.rightChild;
}
return node;
}
Note that in languages like C/C++ you can have pointers to pointer, that allow a much simpler and more efficient implementation of binary trees.

Binary Search Tree Node Removal not removing replacement Java

I am trying to remove nodes from a Binary Search Tree. I can successfully remove any other node on the tree except for one particular case. If the targeted node has 2 children, and the left child has a right subtree, I can locate the correct replacement Node and switch the value to the targeted Node, but then the replacement node is never deleted.
Looking at the picture above, if I try to delete 17, the program will correctly navigate to 13 and replace 17 with 13, but it will not then delete the original 13 as it is supposed to.
I have attached my remove methods and those referenced within.
public Node root;
public void delete(int value){
Node node = new Node<>(value);
Node temp;
if(root == null) {
System.out.println("The tree is already empty!"); //tree is empty
return;
}
if (root.value == node.value) { //Root is target value
temp = node.left;
if(temp.right == null){
node.value = temp.value;
temp = null;
}
else{
while(temp.right != null){
temp = temp.right;
}
node.value = temp.value;
temp = null;
}
return;
}
deleteRec(root, node);
}
private void deleteRec(Node lastRoot, Node node){
Node temp;
if (lastRoot.value >= node.value){
if (lastRoot.left.value == node.value){
node = lastRoot.left;
if(node.left == null && node.right == null){ //No children
node = null;
lastRoot.left = null;
}
else if(node.left == null && node.right != null){ //Right Child
lastRoot.left = node.right;
node = null;
lastRoot.left = null;
}
else if(node.left != null && node.right == null){ //Left Child
lastRoot.left = node.left;
node = null;
}
else{ //Two Children
if(node.left.right == null){
node.value = node.left.value;
node.left = node.left.left;
node.left = null;
}
else{
node = findReplacement(node.left);
lastRoot.left.value = node.value;
node.left = null;
}
}
}
else{
deleteRec(lastRoot.left, node);
}
}
else{
if (lastRoot.right.value == node.value){
node = lastRoot.right;
if(node.left == null && node.right == null){ //No Children
node = null;
lastRoot.right = null;
}
else if(node.left == null && node.right != null){ //Right Child
lastRoot.left = node.right;
node = null;
lastRoot.right = null;
}
else if(node.left != null && node.right == null){ //Left Child
lastRoot.right = node.left;
node = null;
}
else{ //Two Children
if(node.left.right == null){
node.value = node.left.value;
node.left = node.left.left;
node.left = null;
}
else{
node = findReplacement(node.left);
lastRoot.left.value = node.value;
node.left = null;
}
}
}
else{
deleteRec(lastRoot.right, node);
}
}
}
private Node findReplacement(Node node) {
while(node.right != null){
node = node.right;
}
return node;
}
And here is my Node class:
public class Node<T> {
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int value) {
this.value = value;
}
}
Consider this part of your code:
Node rep = findReplacement(node.left);
node.value = rep.value;
rep = null;
You're finding the replacement, and making rep point to it. Then, essentially what you're doing is making rep point to null. This doesn't remove the node! The parent is still pointing to it!
There are several places in your code where you're doing something along these lines. The way you're expected to remove nodes from a tree in this Java implementation is by changing what parents point to. The garbage collector takes care of the other details. I hope addressing this issue helps you resolve your problem!

Finding node in binary tree

Disclaimer: This is for a problem I am stuck with on a homework assignment. I need to refactor my add method and my findnodelocation method so that when finddnodelocation returns the parent node of where the new value would be added, it goes ahead and uses the add method to add the value to the binary search tree where it needs to go.
public void add(int val) {
/*Adds a new node to the binary tree after traversing the tree and figuring out where it belongs*/
Node nodeObjToAdd = new Node(val);
if(root == null){
//if node root is not null root = new node value
root = nodeObjToAdd;
}
Node nodeTraversed = root;
traverseAdd(nodeTraversed, nodeObjToAdd);
}
public Node findNodeLocation(Node focusNode, int val) {
/*returns where a new node with the given value will be placed based on the RootNode, and passed in value.*/
if(val < focusNode.value && focusNode.leftChild != null){
return focusNode.leftChild;
}
if(val >= focusNode.value && focusNode.rightChild != null){
return focusNode.rightChild;
}
else
return this.root;
}
You need to check the data IN the node, before movingo to another node. It goes like this:
// Case where the data would be child of my left child
if(data < node.Data && node.leftChild != null)
return node.leftChild.find(data);
// Case where the data would be child of my right child
if(data >= node.data && node.rigthChild != null)
return node.rightChild.find(data);
// If it is not a child of either, then it would be added as my own child
else
return this;

Iterate through binary search tree to find all leaves

I am pretty new to trees, and I am trying to create kind of a "leaf iterator". I'm thinking it should put all nodes that does not have a .left and .right value onto a stack, but I'm not sure how or even if it's the right thing to do. I have tried searching for it, but every example I come over starts with going to the leftmost leaf, and going p = node.parent, and I am avoiding linking to the node's parent.
I don't understand how I can repeatedlty start from the root and go through the vines without visiting the same vines over and over.
EDIT
I see people suggests using a recursive method to solve this, and I agree now. But I have been banging my head trying to find the solution for an iterator-class-way to do this for a while, and I still would like to know if that's possible, and how!
Use recursion:
public void visitNode(Node node) {
if(node.left != null) {
visitNode(node.left);
}
if(node.right != null) {
visitNode(node.right);
}
if(node.left == null && node.right == null) {
//OMG! leaf!
}
}
start it by supplying root:
visitNode(root);
In order to translate this into an Iterator<Node> you'll have to translate recursion to loop and then to traversal with state. Non-trivial, but should give you a lot of fun.
class Node {
public Node left = null;
public Node right = null;
// data and other goodies
}
class Tree {
public Node root = null;
// add and remove methods, etc.
public void visitAllLeaves(Node root) {
// visit all leaves starting at the root
java.util.Stack<Node> stack = new java.util.Stack<Node>();
if (root == null) return; // check to make sure we're given a good node
stack.push(root);
while (!stack.empty()) {
root = stack.pop();
if (root.left == null && root.right == null) {
// this is a leaf
// do stuff here
}
if (root.left != null) {
stack.push(root.left);
}
if (root.right != null) {
stack.push(root.right);
}
}
}
}
I'm not sure if the above code works, but that's somewhere along the lines of what needs to be done. Another option is javax.swing.TreeModel (half-joking).
Here is how one could implement an Iterator that would only return the leaf nodes, i.e. nodes without a left or right subtree.
The iterator searches for leaf nodes in the tree by doing a depth-first search, remembering the current state of the search in a stack and "pausing" when it has found a leaf node (see fetchNext() method).
The search is resumed when the client "consumes" the leaf node by calling next().
class Node {
public Node left;
public Node right;
}
class LeaveIterator implements Iterator<Node> {
private final Stack<Node> stack = new Stack<>();
private Node nextNode = null;
public LeaveIterator(Node root) {
if (root != null) {
stack.push(root);
nextNode = fetchNext();
}
}
private void fetchNext() {
Node next = null;
while (!stack.isEmpty() && next == null) {
Node node = stack.pop();
if (node.left == null && node.right == null) {
next = node;
}
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return next;
}
public boolean hasNext() {
return nextNode != null;
}
public Node next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Node n = nextNode;
nextNode = fetchNext();
return n;
}
public void remove() {
throw new UnsupportedOperationException();
}
}

Categories

Resources