Itโs good to know that the source code is wrong - I just spent a few hours on it and always thought that something was missing. There is an NPE problem if the root element is passed, and in any case, the removal of the root element is not taken into account.
Here's my Java implementation, which can probably use some optimization, suggestions are welcome. O (n log n) worst case. Tests below.
public boolean remove(final T value0) { BinarySearchTreeNode<T> target = findNode(value0); // Node DNE if (target == null) { return false; } // Both children populated, no need for parent if (target.right != null && target.left != null) { BinarySearchTreeNode<T> max = maxChild(target.left); findParent(max.value).right = null; target.value = max.value; } // Root element targeted, parent DNE else if (target == root) { if (target.right == null && target.left == null) { root = null; } else if (target.right == null) { root = target.left; } else { root = target.right; } } // Non-root, single-child node - find if L or R child, update parent reference. else { BinarySearchTreeNode<T> parent = findParent(value0); if (target.right == null && target.left != null) { if (target.value.compareTo(parent.value) < 0) { parent.left = target.left; } else { parent.right = target.left; } } else if (target.right != null && target.left == null) { if (target.value.compareTo(parent.value) < 0) { parent.left = target.right; } else { parent.right = target.right; } } } return true; }
Unit tests (all pass, obviously):
package BinarySearchTreeTests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; public class Remove { BinarySearchTree<Integer> tree; @Before public void setUp() { tree = new BinarySearchTree<Integer>(); } @Test public void fromEmptyTree() { assertFalse(tree.remove(8)); } @Test public void fromTreeWithOnlyRootNode() { tree.add(10); assertTrue(tree.remove(10)); assertNull(tree.root); } @Test public void nonexistentElement() { tree.add(10); assertFalse(tree.remove(8)); } @Test public void nodeWithNoRightChildren() { tree.add(10); tree.add(5); tree.add(6); tree.add(3); tree.remove(10); assertEquals(tree.root.value, Integer.valueOf(5)); assertEquals(tree.root.left.value, Integer.valueOf(3)); assertEquals(tree.root.right.value, Integer.valueOf(6)); } @Test public void nodeWithNoLeftChildren() { tree.add(10); tree.add(15); tree.add(17); tree.add(13); tree.remove(10); assertEquals(tree.root.value, Integer.valueOf(15)); assertEquals(tree.root.left.value, Integer.valueOf(13)); assertEquals(tree.root.right.value, Integer.valueOf(17)); } @Test public void nodeWithLeftAndRightChildren() { tree.add(10); tree.add(15); tree.add(17); tree.add(13); tree.add(19); tree.add(16); tree.add(14); tree.add(12); tree.remove(15); assertEquals(tree.root.right.value, Integer.valueOf(14)); assertNull(tree.root.right.left.right); } }
Ben Feb 15 '14 at 21:58 2014-02-15 21:58
source share