diff --git a/src/aud/exam/prep/tree/RecursiveOrderedBinaryTreeNodeProcessor.java b/src/aud/exam/prep/tree/RecursiveOrderedBinaryTreeNodeProcessor.java index f8e3397..70d9ee4 100644 --- a/src/aud/exam/prep/tree/RecursiveOrderedBinaryTreeNodeProcessor.java +++ b/src/aud/exam/prep/tree/RecursiveOrderedBinaryTreeNodeProcessor.java @@ -117,8 +117,74 @@ public class RecursiveOrderedBinaryTreeNodeProcessor extends OrderedBinaryTre } @Override - public boolean removeAll(Pointer> tree, V v, Comparator cmp) { - return false; + public boolean removeAll(Pointer> pointer, V v, Comparator cmp) { + var tree = pointer.deref; + + if (tree == null) { + return false; + } + + var c = cmp.compare(v, tree.key); + + if (c == 0) { + if (tree.left == null) { + pointer.deref = tree.right; + } else if (tree.right == null) { + pointer.deref = tree.left; + } else { + tree.key = getReplacementForRemoval(tree.left, tree, false); + } + + removeAll(pointer, v, cmp); + return true; + } + + if (c < 0) { + return removeAllRec(tree.left, v, cmp, tree, false); + } + + return removeAllRec(tree.right, v, cmp, tree, true); + } + + private boolean removeAllRec(BinaryTreeNode node, V v, Comparator cmp, BinaryTreeNode prev, boolean right) { + if (node == null) { + return false; + } + + var c = cmp.compare(v, node.key); + + if (c == 0) { + if (node.left == null) { + if (right) { + prev.right = node.right; + } else { + prev.left = node.right; + } + } else if (node.right == null) { + if (right) { + prev.right = node.left; + } else { + prev.left = node.left; + } + } else { + node.key = getReplacementForRemoval(node.left, node, false); + } + + if (right) { + node = prev.right; + } else { + node = prev.left; + } + + removeAllRec(node, v, cmp, prev, right); + return true; + } + + if (c < 0) { + return removeAllRec(node.left, v, cmp, node, false); + } + + return removeAllRec(node.right, v, cmp, node, true); } @Override diff --git a/test/aud/exam/prep/tree/OrderedTreeProcessorTest.java b/test/aud/exam/prep/tree/OrderedTreeProcessorTest.java index af413c0..7cdaa2a 100644 --- a/test/aud/exam/prep/tree/OrderedTreeProcessorTest.java +++ b/test/aud/exam/prep/tree/OrderedTreeProcessorTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import java.util.Collections; import java.util.List; import static aud.exam.prep.Tests.CMP; @@ -115,6 +116,39 @@ public abstract class OrderedTreeProcessorTest { } } + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeAllOfNonExistsIsFalseAndDoesNotModify(List list) { + T t = asTree(list); + list.sort(CMP); + + var p = new Pointer<>(t); + assertFalse(processor.removeAll(p, -1, CMP)); + assertFalse(processor.removeAll(p, 999, CMP)); + t = p.deref; + + assertTrue(processor.check(t, CMP)); + assertIterableEquals(list, processor.iterate(t)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeAllOfExistsIsTrueAndDoesModify(List list) { + T t = asTree(list); + list.sort(CMP); + + while (!list.isEmpty()) { + var toRemove = list.get(list.size()/2); + list.removeAll(Collections.singleton(toRemove)); + + var p = new Pointer<>(t); + assertTrue(processor.removeAll(p, toRemove, CMP)); + t = p.deref; + + assertTrue(processor.check(t, CMP)); + assertIterableEquals(list, processor.iterate(t)); + } + } @ParameterizedTest @ArgumentsSource(ListProvider.class)