Writing an AVL Tree to hold generics for my data structures course; in my add() method, after actually inserting an element, I step back up through its ancestors checking their scores. For the first few additions it works, but (presumably at the point where balancing does need to be done), the loop back up the path fails to terminate. I've tried everything I can think of to make sure the root of the tree's parent isn't getting set to another node or anything like that. I'm calculating balance scores as right minus left, so positive means a tree is right-heavy and negative means left-heavy. Here's my add():
public void add(T e){
if (e == null)
return;
if (root == null) {
root = new TNode<T>(null, e);
return;
}
boolean added = false;
TNode<T> current = root;
while (current != null && added != true) { //insertion loop
if (current.compareTo(e) == 0)
return;
else if (current.compareTo(e) < 0) {
if (current.getRight() == null) {
current.setRight(new TNode<T>(current, e));
added = true;
}
else
current = current.getRight();
}
else if (current.compareTo(e) > 0) {
if (current.getLeft() == null) {
current.setLeft(new TNode<T>(current, e));
added = true;
}
else
current = current.getLeft();
}
}
if (useAVL == false)
return;
//balancing, checking up from added node to find where tree is unbalanced; currently loop does not terminate
//current is now parent of inserted node
while (current.hasParent()) {
if (current.getAvl() > 1) {
if (current.getRight().getAvl() > 0)
current = rotateLeft(current);
else if (current.getRight().getAvl() < 0) {
current.setRight(rotateRight(current.getRight()));
current = rotateLeft(current);
}
}
if (current.getAvl() < -1) {
if (current.getLeft().getAvl() < 0)
current = rotateRight(current);
else if (current.getLeft().getAvl() > 0) {
current.setLeft(rotateLeft(current.getLeft()));
current = rotateRight(current);
}
}
current = current.getParent();
}
root = current;
root.setParent(null);
}
And here's the right rotation method:
private TNode<T> rotateRight(TNode<T> old) {
TNode<T> oldRoot = old;
TNode<T> newRoot = old.getLeft();
TNode<T> rightChildNewRoot = newRoot.getRight(); //was right child of what will become root, becomes left child of old root
newRoot.setRight(oldRoot);
oldRoot.setParent(newRoot);
oldRoot.setLeft(rightChildNewRoot);
if (rightChildNewRoot != null)
rightChildNewRoot.setParent(oldRoot);
newRoot.setParent(oldRoot.getParent());
return newRoot;
}
Related
I'm currently in the middle of an AVL Tree insert implementation, and I am struggling with maintaining the balance factors while inserting and backtracking up the tree.
Virtually every AVL implementation I can find as an example uses the height of a node's two sub-tree's to calculate the balance factor, something along the lines of
node.balance = node.right.height - node.left.height
And this is perfectly fine if your Node class looks something like
class Node {
int value, height;
Node left, right;
}
Though the problem is that for this particular implementation, it is 'against the rules' to keep track of the height of the node, and instead we can only keep track of the balance factor. So the Node class instead looks like
class Node {
int value, balance;
Node left, right;
}
I know that maintaining the balance factor of a node is conceptually similar to maintaining the height for each insert into the tree, but for the life of me I can't figure out all of the situations in which the balance factor should change for a particular node.
At the moment I've got setting the balance factor implemented by instead recursively calling the height function for each and every node ( not optimal! ) to make sure my rotations and general insertion is correct.
node.balance = height(node.right) - height(node.left)
Where height() recursively traverses the tree to find the longest path to a leaf.
And I have verified that the rotation logic is indeed correct, but when I start writing code to maintain the balances by +-1 increments backtracking up the tree, the code immediately turns into spaghetti, as I am clearly not understanding something fundamental about the node balance factor.
If you want to see that code, I've posted it below ( its a bit long ). And the below implementation is also a String AVL Tree, but the idea is the same.
Any input is appreciated, Thanks!
class StringAVLNode {
private String item;
private int balance;
private StringAVLNode left, right;
// just one constructor, please
public StringAVLNode(String str) {
item = str;
balance = 0;
left = null; right = null;
}
public int getBalance () {
return balance;
}
public void setBalance ( int bal){
balance = bal;
}
public String getItem () {
return item;
}
public StringAVLNode getLeft () {
return left;
}
public void setLeft (StringAVLNode pt){
left = pt;
}
public StringAVLNode getRight () {
return right;
}
public void setRight (StringAVLNode pt){
right = pt;
}
public void insert(String str) {
root = insert(str, root);
}
private StringAVLNode insert(String str, StringAVLNode t) {
// Base case - Just insert the node
if (t == null)
t = new StringAVLNode(str);
else {
int balance, leftChildBalance, rightChildBalance;
leftChildBalance = t.getLeft() != null ? t.getLeft().getBalance() : -99;
rightChildBalance = t.getRight() != null ? t.getRight().getBalance() : -99;
// Perform string comparisons to determine left/right insert
int compareResult = str.compareToIgnoreCase(t.getItem());
if (compareResult < 0) {
t.setLeft(insert(str, t.getLeft()));
if (t.getRight() == null)
t.setBalance(t.getBalance()-1);
else if (leftChildBalance == 0 && t.getLeft().getBalance() != 0)
t.setBalance(t.getBalance()-1);
else if (leftChildBalance == -99 && t.getLeft() != null)
t.setBalance(t.getBalance()-1);
}
else if (compareResult > 0) {
t.setRight(insert(str, t.getRight()));
if (t.getLeft() == null)
t.setBalance(t.getBalance()+1);
else if (rightChildBalance == 0 && t.getRight().getBalance() != 0)
t.setBalance(t.getBalance()+1);
else if (rightChildBalance == -99 && t.getRight() != null)
t.setBalance(t.getBalance()+1);
}
balance = t.getBalance();
// Verbosify booleans
boolean rightImbalance = balance > 1; boolean leftImbalance = balance < -1;
// Imbalance tree situation calls balanceTrees() to handle the rotation logic
// ( Keeps insert() succinct )
if (rightImbalance || leftImbalance)
t = balanceTrees(balance, t);
}
return t;
}
// Rotation Handler
private StringAVLNode balanceTrees(int balance, StringAVLNode t) {
// Verbosify boolean values
boolean rightHeavy = balance > 1; boolean leftHeavy = balance < -1;
boolean requiresDoubleLeft = t.getRight() != null && t.getRight().getBalance() <= -1;
boolean requiresDoubleRight = t.getLeft() != null && t.getLeft().getBalance() >= 1;
if (rightHeavy) {
/** Do double left rotation by right rotating the right child subtree, then
* rotate left
*/
if (requiresDoubleLeft) {
t.setRight(rotateRight(t.getRight()));
t.getRight().setBalance(0);
t = rotateLeft(t);
t.setBalance(0);
}
else {
t = rotateLeft(t);
t.setBalance(0);
if (t.getLeft() != null) t.getLeft().setBalance(0);
if (t.getRight() != null) t.getRight().setBalance(0);
}
}
/** Do double right rotation by left rotating the left child subtree, then
* rotate right
*/
else if (leftHeavy) {
if (requiresDoubleRight) {
t.setLeft(rotateLeft(t.getLeft()));
t.getLeft().setBalance(0);
t = rotateRight(t);
t.setBalance(0);
}
else {
t = rotateRight(t);
t.setBalance(0);
if (t.getLeft() != null) t.getLeft().setBalance(0);
if (t.getRight() != null) t.getRight().setBalance(0);
}
}
if (t.getLeft() != null) {
if (t.getLeft().getRight() != null && t.getLeft().getLeft() == null)
t.getLeft().setBalance(1);
else if (t.getLeft().getLeft() != null && t.getLeft().getRight() == null)
t.getLeft().setBalance(-1);
else if ((t.getLeft().getLeft() != null && t.getLeft().getRight() != null)
|| (t.getLeft().getLeft() == null && t.getLeft().getRight() == null))
t.getLeft().setBalance(0);
}
if (t.getRight() != null) {
if (t.getRight().getRight() != null && t.getRight().getLeft() == null)
t.getRight().setBalance(1);
else if (t.getRight().getLeft() != null && t.getRight().getRight() == null)
t.getRight().setBalance(-1);
else if ((t.getRight().getLeft() != null && t.getRight().getRight() != null)
|| (t.getRight().getLeft() == null && t.getRight().getRight() == null))
t.getRight().setBalance(0);
}
return t;
}
}
Check out my AVL Tree in Java writeup at:
https://debugnotes.wordpress.com/2015/01/07/implementing-an-avl-tree-in-java-part-2
It appears that your implementation does not include any kind of stack based element (recursive or array based) to keep track of how deep you are in the tree. This is a key part of being able to navigate self-balancing tree data structures - being able to search downwards, find and do something with a target node, and then trace backwards to the root node of the tree where it started navigating from, manipulating it as you work your back way up. Using recursion is one way (i.e. using the program stack) or you need to implement your own stack (e.g. use a Queue or LinkedList) but unless your code has a memory structure recording where it's been, unfortunately it'll always get lost.
So I've been trying to insert or add a node to a BST recursively and I'm stumped. I keep getting
Exception in thread "main" java.lang.StackOverflowError
which I'm assuming is being caused by the recursion, but I don't exactly know where to go from here and would love some direction if anyone could help provide it. :)
public void add(Type obj) {
TreeNode<Type> newNode = new TreeNode<Type>(obj);
if (root == null) {
root = newNode;
} else {
addNode(root, newNode);
}
}
private void addNode(TreeNode<Type> current, TreeNode<Type> newNode) {
current = root;
if (current == null) {
current = newNode;
} else if (newNode.getValue().compareTo(current.getValue()) < 0) {
if (current.getLeft() == null) {
current.setLeft(newNode);
} else {
addNode(current.getLeft(), newNode);
}
} else if (newNode.getValue().compareTo(current.getValue()) > 0) {
if (current.getRight() == null) {
current.setRight(newNode);
} else {
addNode(current.getRight(), newNode);
}
}
}//end add
private void addNode(TreeNode<Type> current, TreeNode<Type> newNode) {
current = root;
if (current == null) {
current = newNode;
} else if (newNode.getValue().compareTo(current.getValue()) < 0) {
if (current.getLeft() == null) {
current.setLeft(newNode);
} else {
addNode(current.getLeft(), newNode);
}
Look you are again and again setting the current point equal to root. Which causes StackOverFlow, you should not point to root. You can change it like this: You need to remove this line:
current = root
if(root == null){
root = newNode;
return;
}
First, you're assigning current = root; and then on the next line you're checking:
if (current == null)
This condition will always return false (assuming root is not null).
What you're doing inside the "else if"s is good but you should remove the first if part.
Second, you need to handle the case in which root is null, better do it in a separate method that first check if root is null and only if it's not - calls this method (addNode) with root and the inserted node
Iterator words = treeSearch.getItems().iterator();
int addCount = 0;
while (words.hasNext())
{
numWords++;
rootNode = add(objectToReference, addCount++, (ITreeSearch) words.next(), 0, rootNode);
}
//Add to the Tree
private TernaryTreeNode add(Object storedObject, int wordNum, ITreeSearch treeSearch, int pos, TernaryTreeNode parentNode) throws NoSearchValueSetException
{
if (parentNode == null)
{
parentNode = new TernaryTreeNode(treeSearch.getNodeValue(pos));
}
if (parentNode.lessThan(treeSearch, pos))
{
parentNode.left = add(storedObject, wordNum, treeSearch, pos, parentNode.left);
}
else if (parentNode.greaterThan(treeSearch, pos))
{
parentNode.right = add(storedObject, wordNum, treeSearch, pos, parentNode.right);
}
else
{
if (pos < treeSearch.getNumberNodeValues())
{
parentNode.mid = add(storedObject, wordNum, treeSearch, pos + 1, parentNode.mid);
}
else
{
numberOfObjectsStored++;
parentNode.addStoredData(storedObject);
}
}
return parentNode;
}
This a snippet of my code in my Ternary Tree which I use for inserting a Name of a person(can hav multiple words in a name, like Michele Adams, Tina Joseph George, etc). I want to convert the above recursion to a for loop / while iterator.
Please guide me on this.
General idea in replacing recursion with iteration is to create a state variable, and update it in the loop by following the same rules that you follow in your recursive program. This means that when you pick a left subtree in the recursive program, you update the state to reference the left subtree; when you go to the right subtree, the state changes to reference the right subtree, and so on.
Here is an example of how to rewrite the classic insertion into binary tree without recursion:
public TreeNode add(TreeNode node, int value) {
// Prepare the node that we will eventually insert
TreeNode insert = new TreeNode();
insert.data = value;
// If the parent is null, insert becomes the new parent
if (node == null) {
return insert;
}
// Use current to traverse the tree to the point of insertion
TreeNode current = node;
// Here, current represents the state
while (true) {
// The conditional below will move the state to the left node
// or to the right node, depending on the current state
if (value < current.data) {
if (current.left == null) {
current.left = insert;
break;
} else {
current = current.left;
}
} else {
if (current.right == null) {
current.right = insert;
break;
} else {
current = current.right;
}
}
}
// This is the original node, not the current state
return node;
}
Demo.
Thanks dasblinkenlight..
This is my logic for replacing the above recursive function for a ternary tree.
Iterator words = treeSearch.getItems().iterator();
while (words.hasNext())
{
for (int i = 0; i < word.getNumberNodeValues(); i++)
{
add_Non_Recursive(objectToReference, word, i);
}
}
//Add to Tree
private void add_Non_Recursive(Object storedObject, ITreeSearch treeSearch, int pos) throws NoSearchValueSetException
{
TernaryTreeNode currentNode = rootNode;
// Start from a node(parentNode). If there is no node, then we create a new node to insert into the tree.
// This could even be the root node.
if (rootNode == null)
{
rootNode = new TernaryTreeNode(treeSearch.getNodeValue(pos));
}
else
{
while (currentNode != null)
{
if (currentNode.lessThan(treeSearch, pos))
{
if (currentNode.left == null)
{
currentNode.left = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.left;
}
}
else if (currentNode.greaterThan(treeSearch, pos))
{
if (currentNode.right == null)
{
currentNode.right = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.right;
}
}
else
{
if (currentNode.mid == null)
{
currentNode.mid = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.mid;
}
}
}
}
}
But I dropped this logic as it wasnt great in performing, it took more time than the recursive counterpart.
I am implementing a Red Black Tree with insert, search and delete functions in O (log n) time. Insert and search are working fine. However I am stuck on delete. I found this ppt slide on the internet which shows the algorithm of RBT deletion: http://www.slideshare.net/piotrszymanski/red-black-trees#btnNext on page 56 onwards. I know I am asking a bit too much but I have been stuck on this for over 2 weeks and I can't find the problem. The way I'm understanding Top-Down deletion that you have to rotate and recolor nodes accordingly until you find the predecessor of the node to be deleted. When you do find this node - which would be either a leaf or a node with one right child, replace node to be deleted data by the data of this node and delete this node like normal BST deletion, right?
This is the code I did, based on what I learnt from that slide. If anyone would be so kind to go over it, I would be more than grateful! Or at least if you think there's a better algorithm than what I'm using, please tell me!
public void delete(int element){
if (root == null){
System.out.println("Red Black Tree is Empty!");
} else {
Node X = root;
parent = null;
grandParent = null;
sibling = null;
if (isLeaf(X)){
if (X.getElement() == element){
emptyRBT();
}
} else {
if (checkIfBlack(root.getLeftChild()) && checkIfBlack(root.getRightChild())){
root.setIsBlack(false);
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
}
Step2(X, element);
} else {
Step2B(X, element);
}
}
}
root.setIsBlack(true);
}
public void Step2(Node X, int element)
{
int dir = -1;
while (!isLeaf(X)){
if (predecessor == null){ // still didn't find Node to delete
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
dir = 0;
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
dir = 1;
} else if (X.getElement() == element){
toDelete = X;
predecessor = inorderPredecessor(X.getRightChild());
X = moveRight(X);
}
} else { // if node to delete is already found and X is equal to right node of to delete
// move always to the left until you find predecessor
if (X != predecessor){
X = moveLeft(X);
dir = 0;
}
}
if (!isLeaf(X)){
if (!hasOneNullNode(X)){
if (checkIfBlack(X.getLeftChild()) && checkIfBlack(X.getRightChild())){
Step2A(X, element, dir);
} else {
Step2B(X, element);
}
}
}
}
removeNode(X);
if (predecessor != null){
toDelete.setElement(X.getElement());
}
}
public Node Step2A(Node X, int element, int dir) {
if (checkIfBlack(sibling.getLeftChild()) && checkIfBlack(sibling.getRightChild())) {
X = Step2A1(X);
} else if ((checkIfBlack(sibling.getLeftChild()) == false) && checkIfBlack(sibling.getRightChild())) {
X = Step2A2(X);
} else if ((checkIfBlack(sibling.getLeftChild()) && (checkIfBlack(sibling.getRightChild()) == false))) {
X = Step2A3(X);
} else if ((checkIfBlack(sibling.getLeftChild()) == false) && (checkIfBlack(sibling.getRightChild()) == false)) {
X = Step2A3(X);
}
return X;
}
public Node Step2A1(Node X) {
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
return X;
}
public Node Step2A2(Node X) {
if (parent.getLeftChild() == sibling){
LeftRightRotation(sibling.getLeftChild(), sibling, parent);
} else RightLeftRotation(sibling.getRightChild(), sibling, parent);
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
return X;
}
public Node Step2A3(Node X) {
if (parent.getLeftChild() == sibling){
leftRotate(sibling);
} else if (parent.getRightChild() == sibling){
rightRotate(sibling);
}
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
sibling.getRightChild().setIsBlack(!sibling.getRightChild().IsBlack());
return X;
}
public void Step2B(Node X, int element){
if (predecessor == null){
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
} else if (X.getElement() == element){
Step2(X, element);
}
} else {
if (X != predecessor)
X = moveLeft(X);
else Step2(X, element);
}
if (X.IsBlack()){
if (parent.getLeftChild() == sibling){
leftRotate(sibling);
} else if (parent.getRightChild() == sibling){
rightRotate(sibling);
}
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
Step2(X, element);
} else {
Step2B(X, element);
}
}
public void removeNode(Node X) {
if (isLeaf(X)) {
adjustParentPointer(null, X);
count--;
} else if (X.getLeftChild() != null && X.getRightChild() == null) {
adjustParentPointer(X.getLeftChild(), X);
count--;
} else if (X.getRightChild() != null && X.getLeftChild() == null) {
adjustParentPointer(X.getRightChild(), X);
count--;
}
}
public Node inorderPredecessor(Node node){
while (node.getLeftChild() != null){
node = node.getLeftChild();
}
return node;
}
public void adjustParentPointer(Node node, Node current) {
if (parent != null) {
if (parent.getElement() < current.getElement()) {
parent.setRightChild(node);
} else if (parent.getElement() > current.getElement()) {
parent.setLeftChild(node);
}
} else {
root = node;
}
}
public boolean checkIfBlack(Node n){
if (n == null || n.IsBlack() == true){
return true;
} else return false;
}
public Node leftRotate(Node n)
{
parent.setLeftChild(n.getRightChild());
n.setRightChild(parent);
Node gp = grandParent;
if (gp != null){
if (gp.getElement() > n.getElement()){
gp.setLeftChild(n);
} else if (gp.getElement() < n.getElement()){
gp.setRightChild(n);
}
} else root = n;
return n;
}
public Node rightRotate(Node n)
{
parent.setRightChild(n.getLeftChild());
n.setLeftChild(parent);
Node gp = grandParent;
if (gp != null){
if (gp.getElement() > n.getElement()){
gp.setLeftChild(n);
} else if (gp.getElement() < n.getElement()){
gp.setRightChild(n);
}
} else root = n;
return n;
}
The node is being deleted, but the tree after deletion would be black violated, which is very wrong.
The eternally confuzzled blog has top-down implementations of both insert and delete for red-black trees. It also goes through case-by-case why it works. I won't replicate it here (it's rather lengthy).
I've used that blog as a reference for implementing red-black trees in both c++ and java. As I discussed in an earlier answer, I found the implementation to be faster than std::map's bottom-up implementation of red-black trees (whatever STL came with gcc at the time).
Here's an untested, direct translation of the code to Java. I would highly suggest you test it and morph it to match your style.
private final static int LEFT = 0;
private final static int RIGHT = 1;
private static class Node {
private Node left,right;
private boolean red;
...
// any non-zero argument returns right
Node link(int direction) {
return (direction == LEFT) ? this.left : this.right;
}
// any non-zero argument sets right
Node setLink(int direction, Node n) {
if (direction == LEFT) this.left = n;
else this.right = n;
return n;
}
}
boolean remove(int data) {
if ( this.root != null ) {
final Node head = new Node(-1, null, null); /* False tree root */
Node cur, parent, grandpa; /* Helpers */
Node found = null; /* Found item */
int dir = RIGHT;
/* Set up helpers */
cur = head;
grandpa = parent = null;
cur.setLink(RIGHT, this.root);
/* Search and push a red down */
while ( cur.link(dir) != null ) {
int last = dir;
/* Update helpers */
grandpa = parent, parent = cur;
cur = cur.link(dir);
dir = cur.data < data ? RIGHT : LEFT;
/* Save found node */
if ( cur.data == data )
found = cur;
/* Push the red node down */
if ( !is_red(cur) && !is_red(cur.link(dir)) ) {
if ( is_red(cur.link(~dir)) )
parent = parent.setLink(last, singleRotate(cur, dir));
else if ( !is_red(cur.link(~dir)) ) {
Node s = parent.link(~last);
if ( s != null ) {
if (!is_red(s.link(~last)) && !is_red(s.link(last))) {
/* Color flip */
parent.red = false;
s.red = true;
cur.red = true;
}
else {
int dir2 = grandpa.link(RIGHT) == parent ? RIGHT : LEFT;
if ( is_red(s.link(last)) )
grandpa.setLink(dir2, doubleRotate(parent, last));
else if ( is_red(s.link(~last)) )
grandpa.setLink(dir2, singleRotate(parent, last));
/* Ensure correct coloring */
cur.red = grandpa.link(dir2).red = true;
grandpa.link(dir2).link(LEFT).red = false;
grandpa.link(dir2).link(RIGHT).red = false;
}
}
}
}
}
/* Replace and remove if found */
if ( found != null ) {
found.data = cur.data;
parent.setLink(
parent.link(RIGHT) == cur ? RIGHT : LEFT,
cur.link(cur.link(LEFT) == null ? RIGHT : LEFT));
}
/* Update root and make it black */
this.root = head.link(RIGHT);
if ( this.root != null )
this.root.red = false;
}
return true;
}
quick link :
http://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
--> Caution : the code on the site is relying on two jars. In the datastructures however the dependency might be minimal. Sometimes it's enough to comment out the main method (that only serves as a test client)
If not : the jars are downloadable on the same site.
If you are looking for two weeks and studying algoritms, chances are you know about
http://algs4.cs.princeton.edu/
the website that is accompanying the famous
Algorithms, by Robert Sedgewick and Kevin Wayne
book.
On this website, there is this implementation of a red black (balances) tree :
http://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
I didnot look into it yet (I will later on this year) , but I fully trust it to be a working implementation of a RBTree.
Some sidenote that might be interesting for visitors of this topic:
MIT placed excellent courses concerning algoritms online. The one concerning rbtrees is
http://www.youtube.com/watch?v=iumaOUqoSCk
This is the last case where the node to be deleted has two children. I cant figure out what I am doing wrong . Please help.
//BTNode has two children
else if (u.getLeft() != null && u.getRight() != null){
//if node to delete is root
BTNode<MyEntry<K,V>> pred = u.getRight();
while (pred.getLeft().element() != null){
pred = pred.getLeft();
}
BTNode<MyEntry<K,V>> predParent = pred.getParent();
if (!hasRightChild(pred)){
predParent.setLeft(new BTNode<MyEntry<K,V>>(null,predParent,null,null));}
if (hasRightChild(pred)){
BTNode<MyEntry<K,V>> predChild = pred.getRight();
predParent.setLeft(predChild);
predChild.setParent(predParent);
}
return returnValue;
ok so modify it like this ??
u.setElement(succ.element());
BTNode<MyEntry<K,V>> succParent = succ.getParent();
if (!hasLeftChild(succ)){
succParent.setRight(new BTNode<MyEntry<K,V>>(null,succParent,null,null));}
if (hasLeftChild(succ)){
BTNode<MyEntry<K,V>> predChild = succ.getLeft();
succParent.setRight(predChild);
predChild.setParent(succParent);
}
return returnValue;
From wikipedia:
Deleting a node with two children: Call the node to be deleted N. Do
not delete N. Instead, choose either its in-order successor node or
its in-order predecessor node, R. Replace the value of N with the
value of R, then delete R.
So, take for example the left children, and then find the rightmost leaf in that subtree, then replace the information of the node to delete with that of the leaf, and then delete that leaf easily.
You might want to create a function that returns the rightmost leaf from a subtree.
I have given the code for deletion of a node in a BST which would work for any condition and that too using a for loop.
public void delete(int key) {
Node<E> temp = find(key);
System.out.println(temp.key);
for (;;) {
// case 1 : external node
if (temp.isExternal()) {
if (temp.getParent().getrChild() == temp) {
temp.parent.rightchild = null;
temp = null;
} else {
temp = null;
}
break;
}
// case2 : one child is null
else if ((temp.getlChild() == null) || (temp.getrChild() == null)) {
if ((temp.parent.leftchild != null) && temp.getParent().getlChild().key == temp.key) {
if (temp.getlChild() == null) {
temp.getParent().setLeft(temp.getrChild());
temp.getrChild().setParent(temp.getParent());
break;
}
else
temp.getParent().setLeft(temp.getlChild());
temp.getlChild().setParent(temp.getParent());
}
else {
if (temp.rightchild != null) {
System.out.println("in");
temp.getParent().setRight(temp.getrChild());
temp.getrChild().setParent(temp.getParent());
break;
}
else
temp.getParent().setRight(temp.getlChild());
temp.getlChild().setParent(temp.getParent());
}
break;
}
// case 3 : has both the children
else {
int t = temp.key;
temp.key = temp.getlChild().key;
temp.getlChild().key = t;
temp = temp.getlChild();
continue;
}
}
}