package bjc.utils.funcdata.bst; import java.util.Comparator; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import static bjc.utils.funcdata.bst.DirectedWalkFunction.DirectedWalkResult.FAILURE; import static bjc.utils.funcdata.bst.DirectedWalkFunction.DirectedWalkResult.LEFT; import static bjc.utils.funcdata.bst.DirectedWalkFunction.DirectedWalkResult.RIGHT; import static bjc.utils.funcdata.bst.DirectedWalkFunction.DirectedWalkResult.SUCCESS; /** * A binary node in a tree. * * @author ben * * @param * The data type stored in the tree. */ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { /* * The left child of this node */ private ITreePart left; /* * The right child of this node */ private ITreePart right; /** * Create a new node with the specified data and children. * * @param element * The data to store in this node. * @param lft * The left child of this node. * @param rght * The right child of this node. */ public BinarySearchTreeNode(T element, ITreePart lft, ITreePart rght) { super(element); this.left = lft; this.right = rght; } @Override public void add(T element, Comparator comparator) { if(comparator == null) throw new NullPointerException("Comparator must not be null"); switch(comparator.compare(data, element)) { case -1: if(left == null) { left = new BinarySearchTreeNode<>(element, null, null); } else { left.add(element, comparator); } break; case 0: if(isDeleted) { isDeleted = false; } else throw new IllegalArgumentException("Can't add duplicate values"); break; case 1: if(right == null) { right = new BinarySearchTreeNode<>(element, null, null); } else { right.add(element, comparator); } break; default: throw new IllegalStateException("Error: Comparator yielded invalid value"); } } @Override public E collapse(Function nodeCollapser, BiFunction branchCollapser) { if(nodeCollapser == null || branchCollapser == null) throw new NullPointerException("Collapser must not be null"); E collapsedNode = nodeCollapser.apply(data); if(left != null) { E collapsedLeftBranch = left.collapse(nodeCollapser, branchCollapser); if(right != null) { E collapsedRightBranch = right.collapse(nodeCollapser, branchCollapser); E collapsedBranches = branchCollapser.apply(collapsedLeftBranch, collapsedRightBranch); return branchCollapser.apply(collapsedNode, collapsedBranches); } return branchCollapser.apply(collapsedNode, collapsedLeftBranch); } if(right != null) { E collapsedRightBranch = right.collapse(nodeCollapser, branchCollapser); return branchCollapser.apply(collapsedNode, collapsedRightBranch); } return collapsedNode; } @Override public boolean contains(T element, Comparator comparator) { if(comparator == null) throw new NullPointerException("Comparator must not be null"); return directedWalk(currentElement -> { switch(comparator.compare(element, currentElement)) { case -1: return LEFT; case 0: return isDeleted ? FAILURE : SUCCESS; case 1: return RIGHT; default: return FAILURE; } }); } @Override public void delete(T element, Comparator comparator) { if(comparator == null) throw new NullPointerException("Comparator must not be null"); directedWalk(currentElement -> { switch(comparator.compare(data, element)) { case -1: return left == null ? FAILURE : LEFT; case 0: isDeleted = true; return FAILURE; case 1: return right == null ? FAILURE : RIGHT; default: return FAILURE; } }); } @Override public boolean directedWalk(DirectedWalkFunction treeWalker) { if(treeWalker == null) throw new NullPointerException("Walker must not be null"); switch(treeWalker.walk(data)) { case SUCCESS: return true; case LEFT: return left.directedWalk(treeWalker); case RIGHT: return right.directedWalk(treeWalker); case FAILURE: return false; default: return false; } } @Override public boolean forEach(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { if(linearizationMethod == null) throw new NullPointerException("Linearization method must not be null"); else if(traversalPredicate == null) throw new NullPointerException("Predicate must not be null"); switch(linearizationMethod) { case PREORDER: return preorderTraverse(linearizationMethod, traversalPredicate); case INORDER: return inorderTraverse(linearizationMethod, traversalPredicate); case POSTORDER: return postorderTraverse(linearizationMethod, traversalPredicate); default: throw new IllegalArgumentException( "Passed an incorrect TreeLinearizationMethod " + linearizationMethod + ". WAT"); } } private boolean inorderTraverse(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { if(!traverseLeftBranch(linearizationMethod, traversalPredicate)) return false; if(!traverseElement(traversalPredicate)) return false; if(!traverseRightBranch(linearizationMethod, traversalPredicate)) return false; return true; } private boolean postorderTraverse(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { if(!traverseLeftBranch(linearizationMethod, traversalPredicate)) return false; if(!traverseRightBranch(linearizationMethod, traversalPredicate)) return false; if(!traverseElement(traversalPredicate)) return false; return true; } private boolean preorderTraverse(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { if(!traverseElement(traversalPredicate)) return false; if(!traverseLeftBranch(linearizationMethod, traversalPredicate)) return false; if(!traverseRightBranch(linearizationMethod, traversalPredicate)) return false; return true; } private boolean traverseElement(Predicate traversalPredicate) { boolean nodeSuccesfullyTraversed; if(isDeleted) { nodeSuccesfullyTraversed = true; } else { nodeSuccesfullyTraversed = traversalPredicate.test(data); } return nodeSuccesfullyTraversed; } private boolean traverseLeftBranch(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { boolean leftSuccesfullyTraversed; if(left == null) { leftSuccesfullyTraversed = true; } else { leftSuccesfullyTraversed = left.forEach(linearizationMethod, traversalPredicate); } return leftSuccesfullyTraversed; } private boolean traverseRightBranch(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { boolean rightSuccesfullyTraversed; if(right == null) { rightSuccesfullyTraversed = true; } else { rightSuccesfullyTraversed = right.forEach(linearizationMethod, traversalPredicate); } return rightSuccesfullyTraversed; } }