package binarytree; import exceptions.BoundaryViolationException; import exceptions.EmptyTreeException; import exceptions.InvalidPositionException; import exceptions.NonEmptyTreeException; import position.NodePositionList; import position.Position; import position.PositionList; import java.util.Iterator; public class LinkedBinaryTree implements BinaryTree { protected BTPosition root; protected int size; public LinkedBinaryTree() { root = null; size = 0; } public int size() { return size; } public boolean isEmpty() { return (size == 0); } public boolean isInternal(Position v) throws InvalidPositionException { checkPosition(v); return (hasLeft(v) || hasRight(v)); } public boolean isExternal(Position v) throws InvalidPositionException { return !isInternal(v); } public boolean isRoot(Position v) throws InvalidPositionException { checkPosition(v); return (v == root()); } public boolean hasLeft(Position v) throws InvalidPositionException { BTPosition vv = checkPosition(v); return (vv.getLeft() != null); } public boolean hasRight(Position v) throws InvalidPositionException { BTPosition vv = checkPosition(v); return (vv.getRight() != null); } public Position root() throws EmptyTreeException { if (root == null) throw new EmptyTreeException("The tree is empty"); return root; } public Position left(Position v) throws InvalidPositionException, BoundaryViolationException { BTPosition vv = checkPosition(v); Position leftPos = vv.getLeft(); if (leftPos == null) throw new BoundaryViolationException("No left child"); return leftPos; } public Position right(Position v) throws InvalidPositionException, BoundaryViolationException { BTPosition vv = checkPosition(v); Position rightPos = vv.getRight(); if (rightPos == null) throw new BoundaryViolationException("No right child"); return rightPos; } public Position parent(Position v) throws InvalidPositionException, BoundaryViolationException { BTPosition vv = checkPosition(v); Position parentPos = vv.getParent(); if (parentPos == null) throw new BoundaryViolationException("No parent"); return parentPos; } public Iterable> children(Position v) throws InvalidPositionException { PositionList> children = new NodePositionList>(); if (hasLeft(v)) children.addLast(left(v)); if (hasRight(v)) children.addLast(right(v)); return children; } public Iterable> positions() { PositionList> positions = new NodePositionList>(); if(size != 0) preorderPositions(root(), positions); return positions; } public Iterator iterator() { Iterable> positions = positions(); PositionList elements = new NodePositionList(); for (Position pos: positions) elements.addLast(pos.element()); return elements.iterator(); } public E replace(Position v, E o) throws InvalidPositionException { BTPosition vv = checkPosition(v); E temp = v.element(); vv.setElement(o); return temp; } public Position sibling(Position v) throws InvalidPositionException, BoundaryViolationException { BTPosition vv = checkPosition(v); BTPosition parentPos = vv.getParent(); if (parentPos != null) { BTPosition sibPos; BTPosition leftPos = parentPos.getLeft(); if (leftPos == vv) sibPos = parentPos.getRight(); else sibPos = parentPos.getLeft(); if (sibPos != null) return sibPos; } throw new BoundaryViolationException("No sibling"); } public Position addRoot(E e) throws NonEmptyTreeException { if(!isEmpty()) throw new NonEmptyTreeException("Tree already has a root"); size = 1; root = createNode(e,null,null,null); return root; } public Position insertLeft(Position v, E e) throws InvalidPositionException { BTPosition vv = checkPosition(v); Position leftPos = vv.getLeft(); if (leftPos != null) throw new InvalidPositionException("Node already has a left child"); BTPosition ww = createNode(e, vv, null, null); vv.setLeft(ww); size++; return ww; } public Position insertRight(Position v, E e) throws InvalidPositionException { BTPosition vv = checkPosition(v); Position rightPos = vv.getRight(); if (rightPos != null) throw new InvalidPositionException("Node already has a right child"); BTPosition w = createNode(e, vv, null, null); vv.setRight(w); size++; return w; } public E remove(Position v) throws InvalidPositionException { BTPosition vv = checkPosition(v); BTPosition leftPos = vv.getLeft(); BTPosition rightPos = vv.getRight(); if (leftPos != null && rightPos != null) throw new InvalidPositionException("Cannot remove node with two children"); BTPosition ww; if (leftPos != null) ww = leftPos; else if (rightPos != null) ww = rightPos; else ww = null; if (vv == root) { if (ww != null) ww.setParent(null); root = ww; } else { BTPosition uu = vv.getParent(); if (vv == uu.getLeft()) uu.setLeft(ww); else uu.setRight(ww); if(ww != null) ww.setParent(uu); } size--; return v.element(); } /** Attaches two trees to be subtrees of an external node. */ public void attach(Position v, BinaryTree T1, BinaryTree T2) throws InvalidPositionException { BTPosition vv = checkPosition(v); if (isInternal(v)) throw new InvalidPositionException("Cannot attach from internal node"); int newSize = size + T1.size() + T2.size(); if (!T1.isEmpty()) { BTPosition r1 = checkPosition(T1.root()); vv.setLeft(r1); r1.setParent(vv); } if (!T2.isEmpty()) { BTPosition r2 = checkPosition(T2.root()); vv.setRight(r2); r2.setParent(vv); } size = newSize; } public void swapElements(Position v, Position w) throws InvalidPositionException { BTPosition vv = checkPosition(v); BTPosition ww = checkPosition(w); E temp = w.element(); ww.setElement(v.element()); vv.setElement(temp); } public void expandExternal(Position v, E l, E r) throws InvalidPositionException { checkPosition(v); if (!isExternal(v)) throw new InvalidPositionException("Node is not external"); insertLeft(v, l); insertRight(v, r); } public void removeAboveExternal(Position v) throws InvalidPositionException { checkPosition(v); if (!isExternal(v)) throw new InvalidPositionException("Node is not external"); if (isRoot(v)) remove(v); else { Position u = parent(v); remove(v); remove(u); } } public void attachLeaves (PositionList L) { if (!isEmpty()) attachLeaves_r(root(),L); } protected void attachLeaves_r(Position v, PositionList L) throws InvalidPositionException { BTPositionvv = checkPosition(v); if (hasLeft(v)) attachLeaves_r(left(v), L); if (hasRight(v)) attachLeaves_r(right(v), L); if (isExternal(v)){ BTPosition a = createNode( L.remove(L.first()) ,vv,null,null); BTPosition b = createNode( L.remove(L.first()) ,vv,null,null); vv.setLeft(a); vv.setRight(b); size+=2; } } // Other methods protected BTPosition checkPosition(Position v) throws InvalidPositionException { if (v == null || !(v instanceof BTPosition) || isEmpty() ) throw new InvalidPositionException("The position is invalid"); return (BTPosition) v; } protected BTPosition createNode(E element, BTPosition parent, BTPosition left, BTPosition right) { return new BTNode(element,parent,left,right); } protected void preorderPositions(Position v, PositionList> pos) throws InvalidPositionException { pos.addLast(v); if (hasLeft(v)) preorderPositions(left(v), pos); if (hasRight(v)) preorderPositions(right(v), pos); } protected void inorderPositions(Position v, PositionList> pos) throws InvalidPositionException { if (hasLeft(v)) inorderPositions(left(v), pos); pos.addLast(v); if (hasRight(v)) inorderPositions(right(v), pos); } @Override public String toString() { return super.toString(); } }