From 6f92828c962d175bf4007f1d24f1e5614fcbb012 Mon Sep 17 00:00:00 2001 From: Giovanni Di Grezia Date: Mon, 24 Mar 2014 18:47:50 +0100 Subject: [PATCH] data_structures_free --- net/datastructures/AVLTree.java | 115 +++++++ net/datastructures/AVLTreeMap.java | 119 +++++++ net/datastructures/ArrayIndexList.java | 75 +++++ .../ArrayListCompleteBinaryTree.java | 192 +++++++++++ net/datastructures/ArrayStack.java | 189 +++++++++++ net/datastructures/BTNode.java | 43 +++ net/datastructures/BTPosition.java | 20 ++ net/datastructures/BinarySearchTree.java | 268 +++++++++++++++ net/datastructures/BinarySearchTreeMap.java | 276 +++++++++++++++ net/datastructures/BinaryTree.java | 22 ++ .../BoundaryViolationException.java | 13 + net/datastructures/CompleteBinaryTree.java | 25 ++ net/datastructures/ComponentsDFS.java | 20 ++ net/datastructures/ConnectivityDFS.java | 24 ++ net/datastructures/DFS.java | 101 ++++++ net/datastructures/DLNode.java | 32 ++ net/datastructures/DNode.java | 32 ++ net/datastructures/DecorablePosition.java | 13 + net/datastructures/DefaultComparator.java | 22 ++ net/datastructures/Deque.java | 45 +++ net/datastructures/Dictionary.java | 46 +++ net/datastructures/Dijkstra.java | 97 ++++++ net/datastructures/Edge.java | 6 + net/datastructures/ElementIterator.java | 45 +++ net/datastructures/EmptyDequeException.java | 16 + net/datastructures/EmptyListException.java | 11 + .../EmptyPriorityQueueException.java | 11 + net/datastructures/EmptyQueueException.java | 15 + net/datastructures/EmptyStackException.java | 16 + net/datastructures/EmptyTreeException.java | 11 + net/datastructures/Entry.java | 11 + net/datastructures/EulerTour.java | 49 +++ net/datastructures/FindCycleDFS.java | 54 +++ net/datastructures/FindPathDFS.java | 38 +++ net/datastructures/FullStackException.java | 13 + net/datastructures/Graph.java | 47 +++ net/datastructures/HashTableMap.java | 177 ++++++++++ net/datastructures/HeapPriorityQueue.java | 128 +++++++ net/datastructures/IndexList.java | 33 ++ net/datastructures/InvalidEntryException.java | 10 + net/datastructures/InvalidKeyException.java | 11 + .../InvalidPositionException.java | 18 + net/datastructures/LinkedBinaryTree.java | 314 ++++++++++++++++++ net/datastructures/LinkedTree.java | 138 ++++++++ net/datastructures/Map.java | 36 ++ net/datastructures/Node.java | 39 +++ net/datastructures/NodeDeque.java | 113 +++++++ net/datastructures/NodePositionList.java | 232 +++++++++++++ net/datastructures/NodeQueue.java | 128 +++++++ net/datastructures/NodeStack.java | 116 +++++++ net/datastructures/NonEmptyTreeException.java | 11 + net/datastructures/Position.java | 12 + net/datastructures/PositionList.java | 50 +++ net/datastructures/PriorityQueue.java | 17 + net/datastructures/Queue.java | 43 +++ net/datastructures/RBTree.java | 219 ++++++++++++ net/datastructures/RBTreeMap.java | 225 +++++++++++++ net/datastructures/Sequence.java | 17 + net/datastructures/Sort.java | 254 ++++++++++++++ .../SortedListPriorityQueue.java | 117 +++++++ net/datastructures/Stack.java | 44 +++ net/datastructures/Tree.java | 41 +++ net/datastructures/TreeNode.java | 39 +++ net/datastructures/TreePosition.java | 18 + net/datastructures/Vertex.java | 6 + 65 files changed, 4738 insertions(+) create mode 100644 net/datastructures/AVLTree.java create mode 100644 net/datastructures/AVLTreeMap.java create mode 100644 net/datastructures/ArrayIndexList.java create mode 100644 net/datastructures/ArrayListCompleteBinaryTree.java create mode 100644 net/datastructures/ArrayStack.java create mode 100644 net/datastructures/BTNode.java create mode 100644 net/datastructures/BTPosition.java create mode 100644 net/datastructures/BinarySearchTree.java create mode 100644 net/datastructures/BinarySearchTreeMap.java create mode 100644 net/datastructures/BinaryTree.java create mode 100644 net/datastructures/BoundaryViolationException.java create mode 100644 net/datastructures/CompleteBinaryTree.java create mode 100644 net/datastructures/ComponentsDFS.java create mode 100644 net/datastructures/ConnectivityDFS.java create mode 100644 net/datastructures/DFS.java create mode 100644 net/datastructures/DLNode.java create mode 100644 net/datastructures/DNode.java create mode 100644 net/datastructures/DecorablePosition.java create mode 100644 net/datastructures/DefaultComparator.java create mode 100644 net/datastructures/Deque.java create mode 100644 net/datastructures/Dictionary.java create mode 100644 net/datastructures/Dijkstra.java create mode 100644 net/datastructures/Edge.java create mode 100644 net/datastructures/ElementIterator.java create mode 100644 net/datastructures/EmptyDequeException.java create mode 100644 net/datastructures/EmptyListException.java create mode 100644 net/datastructures/EmptyPriorityQueueException.java create mode 100644 net/datastructures/EmptyQueueException.java create mode 100644 net/datastructures/EmptyStackException.java create mode 100644 net/datastructures/EmptyTreeException.java create mode 100644 net/datastructures/Entry.java create mode 100644 net/datastructures/EulerTour.java create mode 100644 net/datastructures/FindCycleDFS.java create mode 100644 net/datastructures/FindPathDFS.java create mode 100644 net/datastructures/FullStackException.java create mode 100644 net/datastructures/Graph.java create mode 100644 net/datastructures/HashTableMap.java create mode 100644 net/datastructures/HeapPriorityQueue.java create mode 100644 net/datastructures/IndexList.java create mode 100644 net/datastructures/InvalidEntryException.java create mode 100644 net/datastructures/InvalidKeyException.java create mode 100644 net/datastructures/InvalidPositionException.java create mode 100644 net/datastructures/LinkedBinaryTree.java create mode 100644 net/datastructures/LinkedTree.java create mode 100644 net/datastructures/Map.java create mode 100644 net/datastructures/Node.java create mode 100644 net/datastructures/NodeDeque.java create mode 100644 net/datastructures/NodePositionList.java create mode 100644 net/datastructures/NodeQueue.java create mode 100644 net/datastructures/NodeStack.java create mode 100644 net/datastructures/NonEmptyTreeException.java create mode 100644 net/datastructures/Position.java create mode 100644 net/datastructures/PositionList.java create mode 100644 net/datastructures/PriorityQueue.java create mode 100644 net/datastructures/Queue.java create mode 100644 net/datastructures/RBTree.java create mode 100644 net/datastructures/RBTreeMap.java create mode 100644 net/datastructures/Sequence.java create mode 100644 net/datastructures/Sort.java create mode 100644 net/datastructures/SortedListPriorityQueue.java create mode 100644 net/datastructures/Stack.java create mode 100644 net/datastructures/Tree.java create mode 100644 net/datastructures/TreeNode.java create mode 100644 net/datastructures/TreePosition.java create mode 100644 net/datastructures/Vertex.java diff --git a/net/datastructures/AVLTree.java b/net/datastructures/AVLTree.java new file mode 100644 index 0000000..423b1b8 --- /dev/null +++ b/net/datastructures/AVLTree.java @@ -0,0 +1,115 @@ +package net.datastructures; +import java.util.Comparator; + +//begin#fragment AVLTree +/** Implementation of an AVL tree. */ +//end#fragment AVLTree +/** + * AVLTree class - implements an AVL Tree by extending a binary + * search tree. + * + * @author Michael Goodrich, Roberto Tamassia, Eric Zamore + */ + +//begin#fragment AVLTree +public class AVLTree + extends BinarySearchTree implements Dictionary { + public AVLTree(Comparator c) { super(c); } + public AVLTree() { super(); } + /** Nested class for the nodes of an AVL tree. */ + protected static class AVLNode extends BTNode> { + protected int height; // we add a height field to a BTNode + AVLNode() {/* default constructor */} + /** Preferred constructor */ + AVLNode(Entry element, BTPosition> parent, + BTPosition> left, BTPosition> right) { + super(element, parent, left, right); + height = 0; + if (left != null) + height = Math.max(height, 1 + ((AVLNode) left).getHeight()); + if (right != null) + height = Math.max(height, 1 + ((AVLNode) right).getHeight()); + } // we assume that the parent will revise its height if needed + public void setHeight(int h) { height = h; } + public int getHeight() { return height; } + } + /** Creates a new binary search tree node (overrides super's version). */ + protected BTPosition> createNode(Entry element, + BTPosition> parent, BTPosition> left, + BTPosition> right) { + return new AVLNode(element,parent,left,right); // now use AVL nodes + } + /** Returns the height of a node (call back to an AVLNode). */ + protected int height(Position> p) { + return ((AVLNode) p).getHeight(); + } + /** Sets the height of an internal node (call back to an AVLNode). */ + protected void setHeight(Position> p) { + ((AVLNode) p).setHeight(1+Math.max(height(left(p)), height(right(p)))); + } + /** Returns whether a node has balance factor between -1 and 1. */ + protected boolean isBalanced(Position> p) { + int bf = height(left(p)) - height(right(p)); + return ((-1 <= bf) && (bf <= 1)); + } +//end#fragment AVLTree +//begin#fragment AVLTree2 + /** Returns a child of p with height no smaller than that of the other child */ +//end#fragment AVLTree2 + /** + * Return a child of p with height no smaller than that of the + * other child. + */ +//begin#fragment AVLTree2 + protected Position> tallerChild(Position> p) { + if (height(left(p)) > height(right(p))) return left(p); + else if (height(left(p)) < height(right(p))) return right(p); + // equal height children - break tie using parent's type + if (isRoot(p)) return left(p); + if (p == left(parent(p))) return left(p); + else return right(p); + } + /** + * Rebalance method called by insert and remove. Traverses the path from + * zPos to the root. For each node encountered, we recompute its height + * and perform a trinode restructuring if it's unbalanced. + */ + protected void rebalance(Position> zPos) { + if(isInternal(zPos)) + setHeight(zPos); + while (!isRoot(zPos)) { // traverse up the tree towards the root + zPos = parent(zPos); + setHeight(zPos); + if (!isBalanced(zPos)) { + // perform a trinode restructuring at zPos's tallest grandchild + Position> xPos = tallerChild(tallerChild(zPos)); + zPos = restructure(xPos); // tri-node restructure (from parent class) + setHeight(left(zPos)); // recompute heights + setHeight(right(zPos)); + setHeight(zPos); + } + } + } + // overridden methods of the dictionary ADT +//end#fragment AVLTree2 + /** + * Inserts an item into the dictionary and returns the newly created + * entry. + */ +//begin#fragment AVLTree2 + public Entry insert(K k, V v) throws InvalidKeyException { + Entry toReturn = super.insert(k, v); // calls our createNode method + rebalance(actionPos); // rebalance up from the insertion position + return toReturn; + } +//end#fragment AVLTree2 + /** Removes and returns an entry from the dictionary. */ +//begin#fragment AVLTree2 + public Entry remove(Entry ent) throws InvalidEntryException { + Entry toReturn = super.remove(ent); + if (toReturn != null) // we actually removed something + rebalance(actionPos); // rebalance up the tree + return toReturn; + } +} // end of AVLTree class +//end#fragment AVLTree2 diff --git a/net/datastructures/AVLTreeMap.java b/net/datastructures/AVLTreeMap.java new file mode 100644 index 0000000..7c355aa --- /dev/null +++ b/net/datastructures/AVLTreeMap.java @@ -0,0 +1,119 @@ +package net.datastructures; +import java.util.Comparator; + +//begin#fragment AVLTree +/** Implementation of an AVL tree. */ +//end#fragment AVLTree +/** + * AVLTree class - implements an AVL Tree by extending a binary + * search tree. + * + * @author Michael Goodrich, Roberto Tamassia, Eric Zamore + */ + +//begin#fragment AVLTree +public class AVLTreeMap + extends BinarySearchTreeMap implements Map { + public AVLTreeMap(Comparator c) { super(c); } + public AVLTreeMap() { super(); } + /** Nested class for the nodes of an AVL tree. */ + protected static class AVLNode extends BTNode> { + protected int height; // we add a height field to a BTNode + AVLNode() {/* default constructor */} + /** Preferred constructor */ + AVLNode(Entry element, BTPosition> parent, + BTPosition> left, BTPosition> right) { + super(element, parent, left, right); + height = 0; + if (left != null) + height = Math.max(height, 1 + ((AVLNode) left).getHeight()); + if (right != null) + height = Math.max(height, 1 + ((AVLNode) right).getHeight()); + } // we assume that the parent will revise its height if needed + public void setHeight(int h) { height = h; } + public int getHeight() { return height; } + } + /** Creates a new binary search tree node (overrides super's version). */ + protected BTPosition> createNode(Entry element, + BTPosition> parent, BTPosition> left, + BTPosition> right) { + return new AVLNode(element,parent,left,right); // now use AVL nodes + } + /** Returns the height of a node (call back to an AVLNode). */ + protected int height(Position> p) { + return ((AVLNode) p).getHeight(); + } + /** Sets the height of an internal node (call back to an AVLNode). */ + protected void setHeight(Position> p) { + ((AVLNode) p).setHeight(1+Math.max(height(left(p)), height(right(p)))); + } + /** Returns whether a node has balance factor between -1 and 1. */ + protected boolean isBalanced(Position> p) { + int bf = height(left(p)) - height(right(p)); + return ((-1 <= bf) && (bf <= 1)); + } +//end#fragment AVLTree +//begin#fragment AVLTree2 + /** Returns a child of p with height no smaller than that of the other child */ +//end#fragment AVLTree2 + /** + * Return a child of p with height no smaller than that of the + * other child. + */ +//begin#fragment AVLTree2 + protected Position> tallerChild(Position> p) { + if (height(left(p)) > height(right(p))) return left(p); + else if (height(left(p)) < height(right(p))) return right(p); + // equal height children - break tie using parent's type + if (isRoot(p)) return left(p); + if (p == left(parent(p))) return left(p); + else return right(p); + } + /** + * Rebalance method called by insert and remove. Traverses the path from + * zPos to the root. For each node encountered, we recompute its height + * and perform a trinode restructuring if it's unbalanced. + */ + protected void rebalance(Position> zPos) { + if(isInternal(zPos)) + setHeight(zPos); + while (!isRoot(zPos)) { // traverse up the tree towards the root + zPos = parent(zPos); + setHeight(zPos); + if (!isBalanced(zPos)) { + // perform a trinode restructuring at zPos's tallest grandchild + Position> xPos = tallerChild(tallerChild(zPos)); + zPos = restructure(xPos); // tri-node restructure (from parent class) + setHeight(left(zPos)); // recompute heights + setHeight(right(zPos)); + setHeight(zPos); + } + } + } + // overridden methods of the dictionary ADT +//end#fragment AVLTree2 + /** + * If there is an entry with the specified key, replaces the value of + * this entry with the specified value and returns the old value. Else, + * adds a new entry with the specified key and value and returns null. + */ +//begin#fragment AVLTree2 + public V put(K k, V v) throws InvalidKeyException { + V toReturn = super.put(k, v); // calls our createNode method if k is new + rebalance(actionPos); // rebalance up from the insertion position + return toReturn; + } +//end#fragment AVLTree2 + /** + * If there is an entry with the specified key, removes this entry and + * returns its value. Else, returns null. + */ +//begin#fragment AVLTree2 + public V remove(K k) throws InvalidKeyException { + V toReturn = super.remove(k); + if (toReturn != null) // we actually removed something + rebalance(actionPos); // rebalance up the tree + return toReturn; + } +} // end of AVLTree class +//end#fragment AVLTree2 diff --git a/net/datastructures/ArrayIndexList.java b/net/datastructures/ArrayIndexList.java new file mode 100644 index 0000000..3f9c746 --- /dev/null +++ b/net/datastructures/ArrayIndexList.java @@ -0,0 +1,75 @@ +package net.datastructures; +//begin#fragment vector +/** Realization of an indexed list by means of an array, which is doubled + * when the size of the indexed list exceeds the capacity of the array. +//end#fragment vector + * + * @author Roberto Tamassia, Michael Goodrich +//begin#fragment vector + */ +public class ArrayIndexList implements IndexList { + private E[] A; // array storing the elements of the indexed list + private int capacity = 16; // initial length of array A + private int size = 0; // number of elements stored in the indexed list + /** Creates the indexed list with initial capacity 16. */ + public ArrayIndexList() { + A = (E[]) new Object[capacity]; // the compiler may warn, but this is ok + } +//end#fragment vector + /** Returns the number of elements in the indexed list. */ + public int size() { + return size; + } + /** Returns whether the indexed list is empty. */ + public boolean isEmpty() { + return size() == 0; + } + /** Returns the element stored at the given index. */ + public E get(int r) + throws IndexOutOfBoundsException { + checkIndex(r, size()); + return A[r]; + } + /** Replaces the element stored at the given index. */ + public E set(int r, E e) + throws IndexOutOfBoundsException { + checkIndex(r, size()); + E temp = A[r]; + A[r] = e; + return temp; + } +//begin#fragment vector list + /** Inserts an element at the given index. */ + public void add(int r, E e) + throws IndexOutOfBoundsException { + checkIndex(r, size() + 1); + if (size == capacity) { // an overflow + capacity *= 2; + E[] B =(E[]) new Object[capacity]; + for (int i=0; i=r; i--) // shift elements up + A[i+1] = A[i]; + A[r] = e; + size++; + } + /** Removes the element stored at the given index. */ + public E remove(int r) + throws IndexOutOfBoundsException { + checkIndex(r, size()); + E temp = A[r]; + for (int i=r; i= n) + throw new IndexOutOfBoundsException("Illegal index: " + r); + } +} diff --git a/net/datastructures/ArrayListCompleteBinaryTree.java b/net/datastructures/ArrayListCompleteBinaryTree.java new file mode 100644 index 0000000..8995464 --- /dev/null +++ b/net/datastructures/ArrayListCompleteBinaryTree.java @@ -0,0 +1,192 @@ +package net.datastructures; +import java.util.ArrayList; +import java.util.Iterator; +/** + * A speedy implementation of the CompleteBinaryTree interface using + * a vector. Within the vector, there is a null element at rank 0, + * the root of the tree at rank 1, and the rest of the tree is + * contained as follows. If node n has rank i, + * then the left child of n will have rank 2*i, + * and the right child of n will have rank 2*i + + * 1. Traversing the contents of the vector in order of increasing + * rank yields a level-order traversal + * + * @author Michael Goodrich, Eric Zamore + * @see BinaryTree + * @see CompleteBinaryTree + */ + +//begin#fragment VectorHeap +public class ArrayListCompleteBinaryTree + implements CompleteBinaryTree { + protected ArrayList> T; // indexed list of tree positions + /** Nested class for a index list-based complete binary tree node. */ + protected static class BTPos implements Position { + E element; // element stored at this position + int index; // index of this position in the array list + public BTPos(E elt, int i) { + element = elt; + index = i; + } + public E element() { return element; } + public int index() { return index; } + public E setElement(E elt) { + E temp = element; + element = elt; + return temp; + } +//end#fragment VectorHeap + public String toString() { + return("[" + element + "," + index + "]"); + } +//begin#fragment VectorHeap + } + /** default constructor */ + public ArrayListCompleteBinaryTree() { + T = new ArrayList>(); + T.add(0, null); // the location at rank 0 is deliberately empty + } + /** Returns the number of (internal and external) nodes. */ + public int size() { return T.size() - 1; } + /** Returns whether the tree is empty. */ + public boolean isEmpty() { return (size() == 0); } +//end#fragment VectorHeap +//begin#fragment VectorHeap2 + /** Returns whether v is an internal node. */ + public boolean isInternal(Position v) throws InvalidPositionException { + return hasLeft(v); // if v has a right child it will have a left child + } + /** Returns whether v is an external node. */ + public boolean isExternal(Position v) throws InvalidPositionException { + return !isInternal(v); + } + /** Returns whether v is the root node. */ + public boolean isRoot(Position v) throws InvalidPositionException { + BTPos vv = checkPosition(v); + return vv.index() == 1; + } + /** Returns whether v has a left child. */ + public boolean hasLeft(Position v) throws InvalidPositionException { + BTPos vv = checkPosition(v); + return 2*vv.index() <= size(); + } + /** Returns whether v has a right child. */ + public boolean hasRight(Position v) throws InvalidPositionException { + BTPos vv = checkPosition(v); + return 2*vv.index() + 1 <= size(); + } + /** Returns the root of the tree. */ + public Position root() throws EmptyTreeException { + if (isEmpty()) throw new EmptyTreeException("Tree is empty"); + return T.get(1); + } + /** Returns the left child of v. */ + public Position left(Position v) + throws InvalidPositionException, BoundaryViolationException { + if (!hasLeft(v)) throw new BoundaryViolationException("No left child"); + BTPos vv = checkPosition(v); + return T.get(2*vv.index()); + } + /** Returns the right child of v. */ + public Position right(Position v) + throws InvalidPositionException { + if (!hasRight(v)) throw new BoundaryViolationException("No right child"); + BTPos vv = checkPosition(v); + return T.get(2*vv.index() + 1); + } +//end#fragment VectorHeap2 +//begin#fragment VectorHeap3 + /** Returns the parent of v. */ + public Position parent(Position v) + throws InvalidPositionException, BoundaryViolationException { + if (isRoot(v)) throw new BoundaryViolationException("No parent"); + BTPos vv = checkPosition(v); + return T.get(vv.index()/2); + } +//end#fragment VectorHeap3 + /** Returns an iterable collection of the children of v. */ + 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; + } + /** Returns an iterable collection of all the nodes in the tree. */ + public Iterable> positions() { + ArrayList> P = new ArrayList>(); + Iterator> iter = T.iterator(); + iter.next(); // skip the first position + while (iter.hasNext()) + P.add(iter.next()); + return P; + } +//begin#fragment VectorHeap3 + /** Replaces the element at v. */ + public E replace(Position v, E o) throws InvalidPositionException { + BTPos vv = checkPosition(v); + return vv.setElement(o); + } + /** Adds an element just after the last node (in a level numbering). */ + public Position add(E e) { + int i = size() + 1; + BTPos p = new BTPos(e,i); + T.add(i, p); + return p; + } + /** Removes and returns the element at the last node. */ + public E remove() throws EmptyTreeException { + if(isEmpty()) throw new EmptyTreeException("Tree is empty"); + return T.remove(size()).element(); + } + /** Determines whether the given position is a valid node. */ + protected BTPos checkPosition(Position v) + throws InvalidPositionException + { + if (v == null || !(v instanceof BTPos)) + throw new InvalidPositionException("Position is invalid"); + return (BTPos) v; + } +//end#fragment VectorHeap3 + // Additional Methods + /** Returns the sibling of v. */ + public Position sibling(Position v) + throws InvalidPositionException, BoundaryViolationException { + try { + Position p = parent(v); + Position lc = left(p); + if (v == lc) + return right(p); + else + return lc; + } + catch(BoundaryViolationException e) { + throw new BoundaryViolationException("Node has no sibling"); + } + } + /** Swaps the elements at two nodes. */ + public void swapElements(Position v, Position w) + throws InvalidPositionException { + BTPos vv = checkPosition(v); + BTPos ww = checkPosition(w); + E temp = vv.element(); + vv.setElement(ww.element()); + ww.setElement(temp); + } +//begin#fragment VectorHeap3 + /** Returns an iterator of the elements stored at all nodes in the tree. */ + public Iterator iterator() { + ArrayList list = new ArrayList(); + Iterator> iter = T.iterator(); + iter.next(); // skip the first element + while (iter.hasNext()) + list.add(iter.next().element()); + return list.iterator(); + } +//end#fragment VectorHeap3 + /** Returns a String representing this complete binary tree. */ + public String toString() { return T.toString(); } +//begin#fragment VectorHeap3 +} +//end#fragment VectorHeap3 diff --git a/net/datastructures/ArrayStack.java b/net/datastructures/ArrayStack.java new file mode 100644 index 0000000..24e27d8 --- /dev/null +++ b/net/datastructures/ArrayStack.java @@ -0,0 +1,189 @@ +package net.datastructures; +//begin#fragment ArrayStack + /** + * Implementation of the stack ADT using a fixed-length array. An + * exception is thrown if a push operation is attempted when the size + * of the stack is equal to the length of the array. This class + * includes the main methods of the built-in class java.util.Stack. +//end#fragment ArrayStack + * + * @author Natasha Gelfand + * @author Roberto Tamassia + * @see FullStackException +//begin#fragment ArrayStack + */ +//begin#fragment ArrayStack +public class ArrayStack implements Stack { +//end#fragment ArrayStack + /** + * Length of the array used to implement the stack. + */ +//begin#fragment ArrayStack + protected int capacity; // The actual capacity of the stack array +//end#fragment ArrayStack + /** + * Default array capacity. + */ +//begin#fragment ArrayStack + public static final int CAPACITY = 1000; // default array capacity +//end#fragment ArrayStack + /** + * Array used to implement the stack. + */ +//begin#fragment ArrayStack + protected E S[]; // Generic array used to implement the stack +//end#fragment ArrayStack + /** + * Index of the top element of the stack in the array. + */ +//begin#fragment ArrayStack + protected int top = -1; // index for the top of the stack +//end#fragment ArrayStack + /** + * Initializes the stack to use an array of default length. + */ +//begin#fragment ArrayStack + public ArrayStack() { + this(CAPACITY); // default capacity + } +//end#fragment ArrayStack + /** + * Initializes the stack to use an array of given length. + * @param cap length of the array. + */ +//begin#fragment ArrayStack + public ArrayStack(int cap) { + capacity = cap; + S = (E[]) new Object[capacity]; // compiler may give warning, but this is ok + } +//end#fragment ArrayStack + /** + * Returns the number of elements in the stack. + * This method runs in O(1) time. + * @return number of elements in the stack. + */ +//begin#fragment ArrayStack + public int size() { + return (top + 1); + } +//end#fragment ArrayStack + /** + * Testes whether the stack is empty. + * This method runs in O(1) time. + * @return true if the stack is empty, false otherwise. + */ +//begin#fragment ArrayStack + public boolean isEmpty() { + return (top < 0); + } +//end#fragment ArrayStack + /** + * Inserts an element at the top of the stack. + * This method runs in O(1) time. + * @return element inserted. + * @param element element to be inserted. + * @exception FullStackException if the array storing the elements is full. + */ +//begin#fragment ArrayStack + public void push(E element) throws FullStackException { + if (size() == capacity) + throw new FullStackException("Stack is full."); + S[++top] = element; + } +//end#fragment ArrayStack + /** + * Inspects the element at the top of the stack. + * This method runs in O(1) time. + * @return top element in the stack. + * @exception EmptyStackException if the stack is empty. + */ +//begin#fragment ArrayStack + public E top() throws EmptyStackException { + if (isEmpty()) + throw new EmptyStackException("Stack is empty."); + return S[top]; + } +//end#fragment ArrayStack + /** + * Removes the top element from the stack. + * This method runs in O(1) time. + * @return element removed. + * @exception EmptyStackException if the stack is empty. + */ +//begin#fragment ArrayStack + public E pop() throws EmptyStackException { + E element; + if (isEmpty()) + throw new EmptyStackException("Stack is empty."); + element = S[top]; + S[top--] = null; // dereference S[top] for garbage collection. + return element; + } +//end#fragment ArrayStack + + /** + * Returns a string representation of the stack as a list of elements, + * with the top element at the end: [ ... , prev, top ]. + * This method runs in O(n) time, where n is the size of the stack. + * @return textual representation of the stack. + */ +//begin#fragment ArrayStack2 + public String toString() { + String s; + s = "["; + if (size() > 0) s+= S[0]; + if (size() > 1) + for (int i = 1; i <= size()-1; i++) { + s += ", " + S[i]; + } + return s + "]"; + } +//end#fragment ArrayStack2 + /** + * Prints status information about a recent operation and the stack. + * @param op operation performed + * @param element element returned by the operation + * @return information about the operation performed, the element + * returned by the operation and the content of the stack after + * the operation. + */ +//begin#fragment ArrayStack2 +// Prints status information about a recent operation and the stack. + public void status(String op, Object element) { + System.out.print("------> " + op); // print this operation + System.out.println(", returns " + element); // what was returned + System.out.print("result: size = " + size() + ", isEmpty = " + isEmpty()); + System.out.println(", stack: " + this); // contents of the stack + } +//end#fragment ArrayStack2 +//begin#fragment ArrayStack2 + /** + * Test our program by performing a series of operations on stacks, + * printing the operations performed, the returned elements and the + * contents of the stack involved, after each operation. + */ + public static void main(String[] args) { + Object o; + ArrayStack A = new ArrayStack(); + A.status("new ArrayStack A", null); + A.push(7); + A.status("A.push(7)", null); + o = A.pop(); + A.status("A.pop()", o); + A.push(9); + A.status("A.push(9)", null); + o = A.pop(); + A.status("A.pop()", o); + ArrayStack B = new ArrayStack(); + B.status("new ArrayStack B", null); + B.push("Bob"); + B.status("B.push(\"Bob\")", null); + B.push("Alice"); + B.status("B.push(\"Alice\")", null); + o = B.pop(); + B.status("B.pop()", o); + B.push("Eve"); + B.status("B.push(\"Eve\")", null); + } +} +//end#fragment ArrayStack2 diff --git a/net/datastructures/BTNode.java b/net/datastructures/BTNode.java new file mode 100644 index 0000000..e8df7e2 --- /dev/null +++ b/net/datastructures/BTNode.java @@ -0,0 +1,43 @@ +package net.datastructures; +//begin#fragment BTNode +/** + * Class implementing a node of a binary tree by storing references to + * an element, a parent node, a left node, and a right node. +//end#fragment BTNode + * + * @author Luca Vismara, Roberto Tamassia, Michael Goodrich +//begin#fragment BTNode + */ +public class BTNode implements BTPosition { + private E element; // element stored at this node + private BTPosition left, right, parent; // adjacent nodes +//end#fragment BTNode + /** Default constructor */ + public BTNode() { } +//begin#fragment BTNode + /** Main constructor */ + public BTNode(E element, BTPosition parent, + BTPosition left, BTPosition right) { + setElement(element); + setParent(parent); + setLeft(left); + setRight(right); + } + /** Returns the element stored at this position */ + public E element() { return element; } + /** Sets the element stored at this position */ + public void setElement(E o) { element=o; } + /** Returns the left child of this position */ + public BTPosition getLeft() { return left; } + /** Sets the left child of this position */ + public void setLeft(BTPosition v) { left=v; } + /** Returns the right child of this position */ + public BTPosition getRight() { return right; } + /** Sets the right child of this position */ + public void setRight(BTPosition v) { right=v; } + /** Returns the parent of this position */ + public BTPosition getParent() { return parent; } + /** Sets the parent of this position */ + public void setParent(BTPosition v) { parent=v; } +} +//end#fragment BTNode diff --git a/net/datastructures/BTPosition.java b/net/datastructures/BTPosition.java new file mode 100644 index 0000000..9530f08 --- /dev/null +++ b/net/datastructures/BTPosition.java @@ -0,0 +1,20 @@ +package net.datastructures; +//begin#fragment BTPos +/** + * Interface for a node of a binary tree. It maintains an element, a + * parent node, a left node, and a right node. +//end#fragment BTPos + * + * @author Michael Goodrich +//begin#fragment BTPos + */ +public interface BTPosition extends Position { // inherits element() + public void setElement(E o); + public BTPosition getLeft(); + public void setLeft(BTPosition v); + public BTPosition getRight(); + public void setRight(BTPosition v); + public BTPosition getParent(); + public void setParent(BTPosition v); +} +//end#fragment BTPos diff --git a/net/datastructures/BinarySearchTree.java b/net/datastructures/BinarySearchTree.java new file mode 100644 index 0000000..9de1dd4 --- /dev/null +++ b/net/datastructures/BinarySearchTree.java @@ -0,0 +1,268 @@ +package net.datastructures; +import java.util.Comparator; +import java.util.Iterator; + +/** + * Realization of a dictionary by means of a binary search tree. + * @author Michael Goodrich, Eric Zamore + */ + +//begin#fragment BinarySearchTree +// Realization of a dictionary by means of a binary search tree +public class BinarySearchTree + extends LinkedBinaryTree> implements Dictionary { +//end#fragment BinarySearchTree + // Instance variables: +//begin#fragment BinarySearchTree + protected Comparator C; // comparator + protected Position> + actionPos; // insert node or removed node's parent + protected int numEntries = 0; // number of entries + /** Creates a BinarySearchTree with a default comparator. */ + public BinarySearchTree() { + C = new DefaultComparator(); + addRoot(null); + } +//end#fragment BinarySearchTree + /** Creates a BinarySearchTree with the given comparator. */ +//begin#fragment BinarySearchTree + public BinarySearchTree(Comparator c) { + C = c; + addRoot(null); + } + /** Nested class for location-aware binary search tree entries */ + protected static class BSTEntry implements Entry { + protected K key; + protected V value; + protected Position> pos; + BSTEntry() { /* default constructor */ } + BSTEntry(K k, V v, Position> p) { + key = k; value = v; pos = p; + } + public K getKey() { return key; } + public V getValue() { return value; } + public Position> position() { return pos; } + } +//end#fragment BinarySearchTree + // Auxiliary methods: +//begin#fragment BinarySearchTree + /** Extracts the key of the entry at a given node of the tree. */ + protected K key(Position> position) { + return position.element().getKey(); + } + /** Extracts the value of the entry at a given node of the tree. */ + protected V value(Position> position) { + return position.element().getValue(); + } + /** Extracts the entry at a given node of the tree. */ + protected Entry entry(Position> position) { + return position.element(); + } + /** Replaces an entry with a new entry (and reset the entry's location) */ + protected void replaceEntry(Position > pos, Entry ent) { + ((BSTEntry) ent).pos = pos; + replace(pos, ent); + } + //end#fragment BinarySearchTree +//begin#fragment BinarySearchTree2 +/** Checks whether a given key is valid. */ +protected void checkKey(K key) throws InvalidKeyException { + if(key == null) // just a simple test for now + throw new InvalidKeyException("null key"); +} +/** Checks whether a given entry is valid. */ +protected void checkEntry(Entry ent) throws InvalidEntryException { + if(ent == null || !(ent instanceof BSTEntry)) + throw new InvalidEntryException("invalid entry"); +} +/** Auxiliary method for inserting an entry at an external node */ +protected Entry insertAtExternal(Position> v, Entry e) { + expandExternal(v,null,null); + replace(v, e); + numEntries++; + return e; +} +/** Auxiliary method for removing an external node and its parent */ +protected void removeExternal(Position> v) { + removeAboveExternal(v); + numEntries--; +} +/** Auxiliary method used by find, insert, and remove. */ +protected Position> treeSearch(K key, Position> pos) { + if (isExternal(pos)) return pos; // key not found; return external node + else { + K curKey = key(pos); + int comp = C.compare(key, curKey); + if (comp < 0) + return treeSearch(key, left(pos)); // search left subtree + else if (comp > 0) + return treeSearch(key, right(pos)); // search right subtree + return pos; // return internal node where key is found + } +} +//end#fragment BinarySearchTree2 +/** Adds to L all entries in the subtree rooted at v having keys + * equal to k. */ +//begin#fragment BinarySearchTree2 +// Adds to L all entries in the subtree rooted at v having keys equal to k +protected void addAll(PositionList> L, + Position> v, K k) { + if (isExternal(v)) return; + Position> pos = treeSearch(k, v); + if (!isExternal(pos)) { // we found an entry with key equal to k + addAll(L, left(pos), k); + L.addLast(pos.element()); // add entries in inorder + addAll(L, right(pos), k); + } // this recursive algorithm is simple, but it's not the fastest +} +//end#fragment BinarySearchTree2 + //begin#fragment BinarySearchTree3 + // methods of the dictionary ADT + //end#fragment BinarySearchTree3 + /** Returns the number of entries in the tree. */ + //begin#fragment BinarySearchTree3 + public int size() { return numEntries; } + //end#fragment BinarySearchTree3 + /** Returns whether the tree is empty. */ + //begin#fragment BinarySearchTree3 + public boolean isEmpty() { return size() == 0; } + //end#fragment BinarySearchTree3 + /** Returns an entry containing the given key. Returns null if no + * such entry exists. */ + //begin#fragment BinarySearchTree3 + public Entry find(K key) throws InvalidKeyException { + checkKey(key); // may throw an InvalidKeyException + Position> curPos = treeSearch(key, root()); + actionPos = curPos; // node where the search ended + if (isInternal(curPos)) return entry(curPos); + return null; + } + //end#fragment BinarySearchTree3 + /** Returns an iterable collection of all the entries containing the + * given key. */ + //begin#fragment BinarySearchTree3 + public Iterable> findAll(K key) throws InvalidKeyException { + checkKey(key); // may throw an InvalidKeyException + PositionList> L = new NodePositionList>(); + addAll(L, root(), key); + return L; + } + //end#fragment BinarySearchTree3 + /** Inserts an entry into the tree and returns the newly created entry. */ + //begin#fragment BinarySearchTree3 + public Entry insert(K k, V x) throws InvalidKeyException { + checkKey(k); // may throw an InvalidKeyException + Position> insPos = treeSearch(k, root()); + while (!isExternal(insPos)) // iterative search for insertion position + insPos = treeSearch(k, left(insPos)); + actionPos = insPos; // node where the new entry is being inserted + return insertAtExternal(insPos, new BSTEntry(k, x, insPos)); + } + //end#fragment BinarySearchTree3 + /** Removes and returns a given entry. */ + //begin#fragment BinarySearchTree3 + public Entry remove(Entry ent) throws InvalidEntryException { + checkEntry(ent); // may throw an InvalidEntryException + Position> remPos = ((BSTEntry) ent).position(); + Entry toReturn = entry(remPos); // entry to be returned + if (isExternal(left(remPos))) remPos = left(remPos); // left easy case + else if (isExternal(right(remPos))) remPos = right(remPos); // right easy case + else { // entry is at a node with internal children + Position> swapPos = remPos; // find node for moving entry + remPos = right(swapPos); + do + remPos = left(remPos); + while (isInternal(remPos)); + replaceEntry(swapPos, (Entry) parent(remPos).element()); + } + actionPos = sibling(remPos); // sibling of the leaf to be removed + removeExternal(remPos); + return toReturn; + } +//end#fragment BinarySearchTree3 + /** Returns an iterator containing all entries in the tree. */ + public Iterable> entries() { + PositionList> entries = new NodePositionList>(); + Iterable>> positer = positions(); + for (Position> cur: positer) + if (isInternal(cur)) + entries.addLast(cur.element()); + return entries; + } + /** + * Performs a tri-node restructuring. Assumes the nodes are in one + * of following configurations: + * + *
+   *          z=c       z=c        z=a         z=a
+   *         /  \      /  \       /  \        /  \
+   *       y=b  t4   y=a  t4    t1  y=c     t1  y=b
+   *      /  \      /  \           /  \         /  \
+   *    x=a  t3    t1 x=b        x=b  t4       t2 x=c
+   *   /  \          /  \       /  \             /  \
+   *  t1  t2        t2  t3     t2  t3           t3  t4
+   * 
+ * @return the new root of the restructured subtree + */ + protected Position> restructure(Position> x) { + BTPosition> a, b, c, t1, t2, t3, t4; + Position> y = parent(x); // assumes x has a parent + Position> z = parent(y); // assumes y has a parent + boolean xLeft = (x == left(y)); + boolean yLeft = (y == left(z)); + BTPosition> xx = (BTPosition>)x, + yy = (BTPosition>)y, zz = (BTPosition>)z; + if (xLeft && yLeft) { + a = xx; b = yy; c = zz; + t1 = a.getLeft(); t2 = a.getRight(); t3 = b.getRight(); t4 = c.getRight(); + } + else if (!xLeft && yLeft) { + a = yy; b = xx; c = zz; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); + } + else if (xLeft && !yLeft) { + a = zz; b = xx; c = yy; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); + } + else { // right-right + a = zz; b = yy; c = xx; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = c.getLeft(); t4 = c.getRight(); + } + // put b at z's place + if (isRoot(z)) { + root = b; + b.setParent(null); + } + else { + BTPosition> zParent = (BTPosition>)parent(z); + if (z == left(zParent)) { + b.setParent(zParent); + zParent.setLeft(b); + } + else { // z was a right child + b.setParent(zParent); + zParent.setRight(b); + } + } + // place the rest of the nodes and their children + b.setLeft(a); + a.setParent(b); + b.setRight(c); + c.setParent(b); + a.setLeft(t1); + t1.setParent(a); + a.setRight(t2); + t2.setParent(a); + c.setLeft(t3); + t3.setParent(c); + c.setRight(t4); + t4.setParent(c); + // Reset the location-aware entries + ((BSTEntry) a.element()).pos = a; + ((BSTEntry) b.element()).pos = b; + ((BSTEntry) c.element()).pos = c; + return b; // the new root of this subtree + } +//begin#fragment BinarySearchTree3 +} // entries() method is omitted here +//end#fragment BinarySearchTree3 diff --git a/net/datastructures/BinarySearchTreeMap.java b/net/datastructures/BinarySearchTreeMap.java new file mode 100644 index 0000000..8952599 --- /dev/null +++ b/net/datastructures/BinarySearchTreeMap.java @@ -0,0 +1,276 @@ +package net.datastructures; +import java.util.Comparator; +import java.util.Iterator; + +/** + * Realization of a map by means of a binary search tree. + * @author Michael Goodrich, Eric Zamore + */ + +//begin#fragment BinarySearchTree +// Realization of a map by means of a binary search tree +public class BinarySearchTreeMap + extends LinkedBinaryTree> implements Map { +//end#fragment BinarySearchTree + // Instance variables: +//begin#fragment BinarySearchTree + protected Comparator C; // comparator + protected Position> + actionPos; // insert node or removed node's parent + protected int numEntries = 0; // number of entries + /** Creates a BinarySearchTreeMap with a default comparator. */ + public BinarySearchTreeMap() { + C = new DefaultComparator(); + addRoot(null); + } +//end#fragment BinarySearchTree + /** Creates a BinarySearchTreeMap with the given comparator. */ +//begin#fragment BinarySearchTree + public BinarySearchTreeMap(Comparator c) { + C = c; + addRoot(null); + } + /** Nested class for location-aware binary search tree entries */ + protected static class BSTEntry implements Entry { + protected K key; + protected V value; + protected Position> pos; + BSTEntry() { /* default constructor */ } + BSTEntry(K k, V v, Position> p) { + key = k; value = v; pos = p; + } + public K getKey() { return key; } + public V getValue() { return value; } + public Position> position() { return pos; } + } +//end#fragment BinarySearchTree + // Auxiliary methods: +//begin#fragment BinarySearchTree + /** Extracts the key of the entry at a given node of the tree. */ + protected K key(Position> position) { + return position.element().getKey(); + } + /** Extracts the value of the entry at a given node of the tree. */ + protected V value(Position> position) { + return position.element().getValue(); + } + /** Extracts the entry at a given node of the tree. */ + protected Entry entry(Position> position) { + return position.element(); + } +//end#fragment BinarySearchTree +//begin#fragment BinarySearchTree2 +/** Replaces an entry with a new entry (and reset the entry's location) */ +protected V replaceEntry(Position > pos, Entry ent) { + ((BSTEntry) ent).pos = pos; + return replace(pos, ent).getValue(); +} +/** Checks whether a given key is valid. */ +protected void checkKey(K key) throws InvalidKeyException { + if(key == null) // just a simple test for now + throw new InvalidKeyException("null key"); +} +/** Checks whether a given entry is valid. */ +protected void checkEntry(Entry ent) throws InvalidEntryException { + if(ent == null || !(ent instanceof BSTEntry)) + throw new InvalidEntryException("invalid entry"); +} +/** Auxiliary method for inserting an entry at an external node */ +protected Entry insertAtExternal(Position> v, Entry e) { + expandExternal(v,null,null); + replace(v, e); + numEntries++; + return e; +} +/** Auxiliary method for removing an external node and its parent */ +protected void removeExternal(Position> v) { + removeAboveExternal(v); + numEntries--; +} +/** Auxiliary method used by get, put, and remove. */ +protected Position> treeSearch(K key, Position> pos) { + if (isExternal(pos)) return pos; // key not found; return external node + else { + K curKey = key(pos); + int comp = C.compare(key, curKey); + if (comp < 0) + return treeSearch(key, left(pos)); // search left subtree + else if (comp > 0) + return treeSearch(key, right(pos)); // search right subtree + return pos; // return internal node where key is found + } +} +//end#fragment BinarySearchTree2 +/** Adds to L all entries in the subtree rooted at v having keys + * equal to k. */ +//begin#fragment BinarySearchTree3 + // methods of the map ADT +//end#fragment BinarySearchTree3 + /** Returns the number of entries in the tree. */ +//begin#fragment BinarySearchTree3 + public int size() { return numEntries; } +//end#fragment BinarySearchTree3 + /** Returns whether the tree is empty. */ +//begin#fragment BinarySearchTree3 + public boolean isEmpty() { return size() == 0; } +//end#fragment BinarySearchTree3 + /** + * Returns the value of the entry containing the given key. Returns + * null if no such entry exists. + */ +//begin#fragment BinarySearchTree3 + public V get(K key) throws InvalidKeyException { + checkKey(key); // may throw an InvalidKeyException + Position> curPos = treeSearch(key, root()); + actionPos = curPos; // node where the search ended + if (isInternal(curPos)) return value(curPos); + return null; + } +//end#fragment BinarySearchTree3 + /** + * If there is an entry with the specified key, replaces the value of + * this entry with the specified value and returns the old value. Else, + * adds a new entry with the specified key and value and returns null. + */ +//begin#fragment BinarySearchTree3 + public V put(K k, V x) throws InvalidKeyException { + checkKey(k); // may throw an InvalidKeyException + Position> insPos = treeSearch(k, root()); + BSTEntry e = new BSTEntry(k, x, insPos); + actionPos = insPos; // node where the entry is being inserted + if (isExternal(insPos)) { // we need a new node, key is new + insertAtExternal(insPos, e).getValue(); + return null; + } + return replaceEntry(insPos, e); // key already exists + } +//end#fragment BinarySearchTree3 + /** + * If there is an entry with the specified key, removes this entry and + * returns its value. Else, returns null. + */ +//begin#fragment BinarySearchTree3 + public V remove(K k) throws InvalidKeyException { + checkKey(k); // may throw an InvalidKeyException + Position> remPos = treeSearch(k, root()); + if (isExternal(remPos)) return null; // key not found + Entry toReturn = entry(remPos); // old entry + if (isExternal(left(remPos))) remPos = left(remPos); // left easy case + else if (isExternal(right(remPos))) remPos = right(remPos); // right easy case + else { // entry is at a node with internal children + Position> swapPos = remPos; // find node for moving entry + remPos = right(swapPos); + do + remPos = left(remPos); + while (isInternal(remPos)); + replaceEntry(swapPos, (Entry) parent(remPos).element()); + } + actionPos = sibling(remPos); // sibling of the leaf to be removed + removeExternal(remPos); + return toReturn.getValue(); + } +//end#fragment BinarySearchTree3 + /** Returns an iterable object containing all keys in the tree. */ + public Iterable keySet() { + PositionList keys = new NodePositionList(); + Iterable>> positer = positions(); + for (Position> cur: positer) + if (isInternal(cur)) + keys.addLast(key(cur)); + return keys; + } + /** Returns an iterable object containing all values in the tree. */ + public Iterable values() { + PositionList vals = new NodePositionList(); + Iterable>> positer = positions(); + for (Position> cur: positer) + if (isInternal(cur)) + vals.addLast(value(cur)); + return vals; + } + /** Returns an iterable object containing all entries in the tree. */ + public Iterable> entrySet() { + PositionList> entries = new NodePositionList>(); + Iterable>> positer = positions(); + for (Position> cur: positer) + if (isInternal(cur)) + entries.addLast(cur.element()); + return entries; + } + /** + * Performs a tri-node restructuring. Assumes the nodes are in one + * of following configurations: + * + *
+   *          z=c       z=c        z=a         z=a
+   *         /  \      /  \       /  \        /  \
+   *       y=b  t4   y=a  t4    t1  y=c     t1  y=b
+   *      /  \      /  \           /  \         /  \
+   *    x=a  t3    t1 x=b        x=b  t4       t2 x=c
+   *   /  \          /  \       /  \             /  \
+   *  t1  t2        t2  t3     t2  t3           t3  t4
+   * 
+ * @return the new root of the restructured subtree + */ + protected Position> restructure(Position> x) { + BTPosition> a, b, c, t1, t2, t3, t4; + Position> y = parent(x); // assumes x has a parent + Position> z = parent(y); // assumes y has a parent + boolean xLeft = (x == left(y)); + boolean yLeft = (y == left(z)); + BTPosition> xx = (BTPosition>)x, + yy = (BTPosition>)y, zz = (BTPosition>)z; + if (xLeft && yLeft) { + a = xx; b = yy; c = zz; + t1 = a.getLeft(); t2 = a.getRight(); t3 = b.getRight(); t4 = c.getRight(); + } + else if (!xLeft && yLeft) { + a = yy; b = xx; c = zz; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); + } + else if (xLeft && !yLeft) { + a = zz; b = xx; c = yy; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); + } + else { // right-right + a = zz; b = yy; c = xx; + t1 = a.getLeft(); t2 = b.getLeft(); t3 = c.getLeft(); t4 = c.getRight(); + } + // put b at z's place + if (isRoot(z)) { + root = b; + b.setParent(null); + } + else { + BTPosition> zParent = (BTPosition>)parent(z); + if (z == left(zParent)) { + b.setParent(zParent); + zParent.setLeft(b); + } + else { // z was a right child + b.setParent(zParent); + zParent.setRight(b); + } + } + // place the rest of the nodes and their children + b.setLeft(a); + a.setParent(b); + b.setRight(c); + c.setParent(b); + a.setLeft(t1); + t1.setParent(a); + a.setRight(t2); + t2.setParent(a); + c.setLeft(t3); + t3.setParent(c); + c.setRight(t4); + t4.setParent(c); + // Reset the location-aware entries + ((BSTEntry) a.element()).pos = a; + ((BSTEntry) b.element()).pos = b; + ((BSTEntry) c.element()).pos = c; + return b; // the new root of this subtree + } +//begin#fragment BinarySearchTree3 +} +//end#fragment BinarySearchTree3 diff --git a/net/datastructures/BinaryTree.java b/net/datastructures/BinaryTree.java new file mode 100644 index 0000000..e048914 --- /dev/null +++ b/net/datastructures/BinaryTree.java @@ -0,0 +1,22 @@ +package net.datastructures; +//begin#fragment Tree +/** + * An interface for a binary tree, where each node can have zero, one, + * or two children. +//end#fragment Tree + * @author Michael Goodrich +//begin#fragment Tree + */ +public interface BinaryTree extends Tree { + /** Returns the left child of a node. */ + public Position left(Position v) + throws InvalidPositionException, BoundaryViolationException; + /** Returns the right child of a node. */ + public Position right(Position v) + throws InvalidPositionException, BoundaryViolationException; + /** Returns whether a node has a left child. */ + public boolean hasLeft(Position v) throws InvalidPositionException; + /** Returns whether a node has a right child. */ + public boolean hasRight(Position v) throws InvalidPositionException; +} +//end#fragment Tree diff --git a/net/datastructures/BoundaryViolationException.java b/net/datastructures/BoundaryViolationException.java new file mode 100644 index 0000000..8319e1f --- /dev/null +++ b/net/datastructures/BoundaryViolationException.java @@ -0,0 +1,13 @@ +package net.datastructures; + +/** + * Signals that the boundaries of a data structure have been illegally + * traversed (e.g. past the end of a list). + * @author Roberto Tamassia + */ + +public class BoundaryViolationException extends RuntimeException { + public BoundaryViolationException (String message) { + super (message); + } +} diff --git a/net/datastructures/CompleteBinaryTree.java b/net/datastructures/CompleteBinaryTree.java new file mode 100644 index 0000000..d9c2fa5 --- /dev/null +++ b/net/datastructures/CompleteBinaryTree.java @@ -0,0 +1,25 @@ +package net.datastructures; +/** + * An interface for a complete binary tree. A binary tree with height + * h is complete if the levels 0,1,2,...,h - + * 1 have the maximum number of nodes possible (that is, level + * i has 2i nodes, for 0 <= i <= + * h - 1) and in level h - 1 all the internal nodes + * are to the left of the external nodes. + * + * @author Michael Goodrich + */ +//begin#fragment HeapTree +public interface CompleteBinaryTree extends BinaryTree { +//end#fragment HeapTree + /** Adds an element to the tree just after the last node. Returns + * the newly created position. */ +//begin#fragment HeapTree + public Position add(E elem); +//end#fragment HeapTree + /** Removes and returns the element stored in the last node of the + * tree. */ +//begin#fragment HeapTree + public E remove(); +} +//end#fragment HeapTree diff --git a/net/datastructures/ComponentsDFS.java b/net/datastructures/ComponentsDFS.java new file mode 100644 index 0000000..333eed1 --- /dev/null +++ b/net/datastructures/ComponentsDFS.java @@ -0,0 +1,20 @@ +package net.datastructures; +import java.util.Iterator; + +//begin#fragment CC +/** This class extends DFS to compute the connected components of a graph. */ +public class ComponentsDFS extends DFS { + protected Integer compNumber; // Connected component number + protected Object COMPONENT = new Object(); // Connected comp. selector + protected void setup() { compNumber = 1; } + protected void startVisit(Vertex v) { v.put(COMPONENT, compNumber);} + protected Integer finalResult(Integer dfsResult) { + for (Vertex v : graph.vertices()) // check for any unvisited vertices + if (v.get(STATUS) == UNVISITED) { + compNumber += 1; // we have found another connected component + dfsTraversal(v); // visit all the vertices of this component + } + return compNumber; + } +} +//end#fragment CC diff --git a/net/datastructures/ConnectivityDFS.java b/net/datastructures/ConnectivityDFS.java new file mode 100644 index 0000000..e413b37 --- /dev/null +++ b/net/datastructures/ConnectivityDFS.java @@ -0,0 +1,24 @@ +package net.datastructures; +import java.util.Iterator; +import java.lang.Boolean; + +//begin#fragment ConnectivityTesterDFS +/** This class specializes DFS to determine whether the graph is connected. */ +public class ConnectivityDFS extends DFS { + protected int reached; +//end#fragment ConnectivityTesterDFS + /** Executes the DFS algorithm. + * @param graph Input graph + * @param start Start vertex + * @param info unused + * @return {@link Boolean} with value true if the graph is + * connected, false otherwise + */ +//begin#fragment ConnectivityTesterDFS + protected void setup() { reached = 0; } + protected void startVisit(Vertex v) { reached++; } + protected Boolean finalResult(Boolean dfsResult) { + return new Boolean(reached == graph.numVertices()); + } +} +//end#fragment ConnectivityTesterDFS diff --git a/net/datastructures/DFS.java b/net/datastructures/DFS.java new file mode 100644 index 0000000..b3f5bda --- /dev/null +++ b/net/datastructures/DFS.java @@ -0,0 +1,101 @@ +package net.datastructures; +import java.util.Iterator; + +//begin#fragment DFS +/** Generic DFS traversal of a graph using the template method pattern. + * Parameterized types: + * V, the type for the elements stored at vertices + * E, the type for the elements stored at edges + * I, the type for the information object passed to the execute method + * R, the type for the result object returned by the DFS + */ +public class DFS { + protected Graph graph; // The graph being traversed + protected Vertex start; // The start vertex for the DFS + protected I info; // Information object passed to DFS + protected R visitResult; // The result of a recursive traversal call + protected static Object STATUS = new Object(); // The status attribute + protected static Object VISITED = new Object(); // Visited value + protected static Object UNVISITED = new Object(); // Unvisited value +//end#fragment DFS + +//begin#fragment DFS2 + /** Execute a depth first search traversal on graph g, starting + * from a start vertex s, passing in an information object (in) */ + public R execute(Graph g, Vertex s, I in) { + graph = g; + start = s; + info = in; + for(Vertex v: graph.vertices()) unVisit(v); // mark vertices as unvisited + for(Edge e: graph.edges()) unVisit(e); // mark edges as unvisited + setup(); // perform any necessary setup prior to DFS traversal + return finalResult(dfsTraversal(start)); + } + /** Recursive template method for a generic DFS traversal. */ + protected R dfsTraversal(Vertex v) { + initResult(); + if (!isDone()) + startVisit(v); + if (!isDone()) { + visit(v); + for (Edge e: graph.incidentEdges(v)) { + if (!isVisited(e)) { + // found an unexplored edge, explore it + visit(e); + Vertex w = graph.opposite(v, e); + if (!isVisited(w)) { + // w is unexplored, this is a discovery edge + traverseDiscovery(e, v); + if (isDone()) break; + visitResult = dfsTraversal(w); // get result from DFS-tree child + if (isDone()) break; + } + else { + // w is explored, this is a back edge + traverseBack(e, v); + if (isDone()) break; + } + } + } + } + if(!isDone()) + finishVisit(v); + return result(); + } + //end#fragment DFS2 + + //begin#fragment decorations + /** Mark a position (vertex or edge) as visited. */ + protected void visit(DecorablePosition p) { p.put(STATUS, VISITED); } + /** Mark a position (vertex or edge) as unvisited. */ + protected void unVisit(DecorablePosition p) { p.put(STATUS, UNVISITED); } + /** Test if a position (vertex or edge) has been visited. */ + protected boolean isVisited(DecorablePosition p) { + return (p.get(STATUS) == VISITED); + } +//end#fragment decorations + + // Auxiliary methods (all initially null) for specializing a generic DFS +//begin#fragment auxiliary + /** Setup method that is called prior to the DFS execution. */ + protected void setup() {} + /** Initializes result (called first, once per vertex visited). */ + protected void initResult() {} + /** Called when we encounter a vertex (v). */ + protected void startVisit(Vertex v) {} + /** Called after we finish the visit for a vertex (v). */ + protected void finishVisit(Vertex v) {} + /** Called when we traverse a discovery edge (e) from a vertex (from). */ + protected void traverseDiscovery(Edge e, Vertex from) {} + /** Called when we traverse a back edge (e) from a vertex (from). */ + protected void traverseBack(Edge e, Vertex from) {} + /** Determines whether the traversal is done early. */ + protected boolean isDone() { return false; /* default value */ } + /** Returns a result of a visit (if needed). */ + protected R result() { return null; /* default value */ } + /** Returns the final result of the DFS execute method. */ + protected R finalResult(R r) { return r; /* default value */ } +//end#fragment auxiliary +//begin#fragment Tail +} // end of DFS class +//end#fragment Tail diff --git a/net/datastructures/DLNode.java b/net/datastructures/DLNode.java new file mode 100644 index 0000000..e686c6e --- /dev/null +++ b/net/datastructures/DLNode.java @@ -0,0 +1,32 @@ +package net.datastructures; + +/** + * A simple node class for a doubly-linked list. Each node has a + * reference to a stored element, a previous node, and a next node. + * This class differs from the DNode class in that it + * does not implement the Position interface, for + * simplification purposes. + * + * @author Roberto Tamassia + * @see DNode + * @see Position + */ + +//begin#fragment DLNode +public class DLNode { + private E element; + private DLNode next, prev; + DLNode() { this(null, null, null); } + DLNode(E e, DLNode p, DLNode n) { + element = e; + next = n; + prev = p; + } + public void setElement(E newElem) { element = newElem; } + public void setNext(DLNode newNext) { next = newNext; } + public void setPrev(DLNode newPrev) { prev = newPrev; } + public E getElement() { return element; } + public DLNode getNext() { return next; } + public DLNode getPrev() { return prev; } +} +//end#fragment DLNode diff --git a/net/datastructures/DNode.java b/net/datastructures/DNode.java new file mode 100644 index 0000000..3d3bad5 --- /dev/null +++ b/net/datastructures/DNode.java @@ -0,0 +1,32 @@ +package net.datastructures; +/** + * A simple node class for a doubly-linked list. Each DNode has a + * reference to a stored element, a previous node, and a next node. + * + * @author Roberto Tamassia + */ +//begin#fragment DNode +public class DNode implements Position { + private DNode prev, next; // References to the nodes before and after + private E element; // Element stored in this position + /** Constructor */ + public DNode(DNode newPrev, DNode newNext, E elem) { + prev = newPrev; + next = newNext; + element = elem; + } + // Method from interface Position + public E element() throws InvalidPositionException { + if ((prev == null) && (next == null)) + throw new InvalidPositionException("Position is not in a list!"); + return element; + } + // Accessor methods + public DNode getNext() { return next; } + public DNode getPrev() { return prev; } + // Update methods + public void setNext(DNode newNext) { next = newNext; } + public void setPrev(DNode newPrev) { prev = newPrev; } + public void setElement(E newElement) { element = newElement; } +} +//end#fragment DNode diff --git a/net/datastructures/DecorablePosition.java b/net/datastructures/DecorablePosition.java new file mode 100644 index 0000000..269a834 --- /dev/null +++ b/net/datastructures/DecorablePosition.java @@ -0,0 +1,13 @@ +package net.datastructures; + +/** + * An interface for a position that can be marked with an arbitrary + * number of decorations. + * + * @author Roberto Tamassia, Michael Goodrich + */ +//begin#fragment Decorable +public interface DecorablePosition + extends Position, Map { +} // no new methods needed -- this is a mixture of Position and Map. +//end#fragment Decorable diff --git a/net/datastructures/DefaultComparator.java b/net/datastructures/DefaultComparator.java new file mode 100644 index 0000000..de63b5f --- /dev/null +++ b/net/datastructures/DefaultComparator.java @@ -0,0 +1,22 @@ +package net.datastructures; +import java.util.Comparator; +import java.io.Serializable; +/** Comparator based on the natural ordering + * + * @author Michael Goodrich + */ +//begin#fragment DefaultComparator +public class DefaultComparator implements Comparator { +//end#fragment DefaultComparator + /** Compares two given elements + * + * @return a negative integer if a is less than b, + * zero if a equals b, or a positive integer if + * a is greater than b + */ +//begin#fragment DefaultComparator + public int compare(E a, E b) throws ClassCastException { + return ((Comparable) a).compareTo(b); + } +} +//end#fragment DefaultComparator diff --git a/net/datastructures/Deque.java b/net/datastructures/Deque.java new file mode 100644 index 0000000..a0e4794 --- /dev/null +++ b/net/datastructures/Deque.java @@ -0,0 +1,45 @@ +package net.datastructures; +//begin#fragment Deque + /** + * Interface for a deque: a collection of objects that are inserted + * and removed at both ends; a subset of java.util.LinkedList methods. + * + * @author Roberto Tamassia + * @author Michael Goodrich + */ + +public interface Deque { + /** + * Returns the number of elements in the deque. + */ + public int size(); + /** + * Returns whether the deque is empty. + */ + public boolean isEmpty(); + /** + * Returns the first element; an exception is thrown if deque is empty. + */ + public E getFirst() throws EmptyDequeException; + /** + * Returns the last element; an exception is thrown if deque is empty. + */ + public E getLast() throws EmptyDequeException; + /** + * Inserts an element to be the first in the deque. + */ + public void addFirst (E element); + /** + * Inserts an element to be the last in the deque. + */ + public void addLast (E element); + /** + * Removes the first element; an exception is thrown if deque is empty. + */ + public E removeFirst() throws EmptyDequeException; + /** + * Removes the last element; an exception is thrown if deque is empty. + */ + public E removeLast() throws EmptyDequeException; +} +//end#fragment Deque diff --git a/net/datastructures/Dictionary.java b/net/datastructures/Dictionary.java new file mode 100644 index 0000000..f5e40c9 --- /dev/null +++ b/net/datastructures/Dictionary.java @@ -0,0 +1,46 @@ +package net.datastructures; +import java.util.Iterator; + +/** + * An interface for a dictionary storing (key-value) pairs. + * @author Michael Goodrich + */ +//begin#fragment Dictionary +public interface Dictionary { +//end#fragment Dictionary + /** Returns the number of entries in the dictionary. */ +//begin#fragment Dictionary + public int size(); +//end#fragment Dictionary + /** Returns whether the dictionary is empty. */ +//begin#fragment Dictionary + public boolean isEmpty(); +//end#fragment Dictionary + /** Returns an entry containing the given key, or null if + * no such entry exists. */ +//begin#fragment Dictionary + public Entry find(K key) + throws InvalidKeyException; +//end#fragment Dictionary + /** Returns an iterator containing all the entries containing the + * given key, or an empty iterator if no such entries exist. */ +//begin#fragment Dictionary + public Iterable> findAll(K key) + throws InvalidKeyException; +//end#fragment Dictionary + /** Inserts an item into the dictionary. Returns the newly created + * entry. */ +//begin#fragment Dictionary + public Entry insert(K key, V value) + throws InvalidKeyException; +//end#fragment Dictionary + /** Removes and returns the given entry from the dictionary. */ +//begin#fragment Dictionary + public Entry remove(Entry e) + throws InvalidEntryException; +//end#fragment Dictionary + /** Returns an iterator containing all the entries in the dictionary. */ +//begin#fragment Dictionary + public Iterable> entries(); +} +//end#fragment Dictionary diff --git a/net/datastructures/Dijkstra.java b/net/datastructures/Dijkstra.java new file mode 100644 index 0000000..0c71952 --- /dev/null +++ b/net/datastructures/Dijkstra.java @@ -0,0 +1,97 @@ +package net.datastructures; +import java.util.Iterator; +import java.lang.reflect.Field; + +/** + * Dijkstra's algorithm for the single-source shortest path problem in + * an undirected graph whose edges have integer weights. + * + *

To execute the algorithm, use the {@link + * #execute(Graph,Vertex,Object) execute} method, and then make + * subsequent calls to the {@link #getDist(Vertex) getDist} method to + * obtain the shortest distance from the start to any given vertex. + * + * @author Roberto Tamassia, Michael Goodrich, Eric Zamore + */ + +//begin#fragment execute +/* Dijkstra's algorithm for the single-source shortest path problem + * in an undirected graph whose edges have non-negative integer weights. */ +public class Dijkstra { + /** Infinity value. */ + protected static final Integer INFINITE = Integer.MAX_VALUE; + /** Input graph. */ + protected Graph graph; + /** Decoration key for edge weights */ + protected Object WEIGHT; + /** Decoration key for vertex distances */ + protected Object DIST = new Object(); + /** Decoration key for entries in the priority queue */ + protected Object ENTRY = new Object(); + /** Auxiliary priority queue. */ + protected AdaptablePriorityQueue> Q; + /** Executes Dijkstra's algorithm. + * @param g Input graph + * @param s Source vertex + * @param w Weight decoration object */ + public void execute(Graph g, Vertex s, Object w) { + graph = g; + WEIGHT = w; + DefaultComparator dc = new DefaultComparator(); + Q = new HeapAdaptablePriorityQueue>(dc); + dijkstraVisit(s); + } + /** Get the distance of a vertex from the source vertex. +//end#fragment execute + * This method returns the length of a shortest path from the source + * to u after {@link #execute(Graph,Vertex,Object) execute} + * has been called. +//begin#fragment execute + * @param u Start vertex for the shortest path tree */ + public int getDist(Vertex u) { + return (Integer) u.get(DIST); + } +//end#fragment execute + + //begin#fragment dijkstraVisit + /** The actual execution of Dijkstra's algorithm. + * @param v source vertex. + */ + protected void dijkstraVisit (Vertex v) { + // store all the vertices in priority queue Q + for (Vertex u: graph.vertices()) { + int u_dist; + if (u==v) + u_dist = 0; + else + u_dist = INFINITE; + Entry> u_entry = Q.insert(u_dist, u); // autoboxing + u.put(ENTRY, u_entry); + } + // grow the cloud, one vertex at a time + while (!Q.isEmpty()) { + // remove from Q and insert into cloud a vertex with minimum distance + Entry> u_entry = Q.min(); + Vertex u = u_entry.getValue(); + int u_dist = u_entry.getKey(); + Q.remove(u_entry); // remove u from the priority queue + u.put(DIST,u_dist); // the distance of u is final + u.remove(ENTRY); // remove the entry decoration of u + if (u_dist == INFINITE) + continue; // unreachable vertices are not processed + // examine all the neighbors of u and update their distances + for (Edge e: graph.incidentEdges(u)) { + Vertex z = graph.opposite(u,e); + Entry> z_entry + = (Entry>) z.get(ENTRY); + if (z_entry != null) { // check that z is in Q, i.e., not in the cloud + int e_weight = (Integer) e.get(WEIGHT); + int z_dist = z_entry.getKey(); + if ( u_dist + e_weight < z_dist ) // relaxation of edge e = (u,z) + Q.replaceKey(z_entry, u_dist + e_weight); + } + } + } + } + //end#fragment dijkstraVisit +} // end of Dijkstra class diff --git a/net/datastructures/Edge.java b/net/datastructures/Edge.java new file mode 100644 index 0000000..9874490 --- /dev/null +++ b/net/datastructures/Edge.java @@ -0,0 +1,6 @@ +package net.datastructures; +/** + * An interface for an edge of a graph. + * @author Roberto Tamassia + */ +public interface Edge extends DecorablePosition { } diff --git a/net/datastructures/ElementIterator.java b/net/datastructures/ElementIterator.java new file mode 100644 index 0000000..43208fe --- /dev/null +++ b/net/datastructures/ElementIterator.java @@ -0,0 +1,45 @@ +package net.datastructures; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.lang.UnsupportedOperationException; + +/** + * A simple iterator class for lists. The elements of a list are + * returned by this iterator. No copy of the list is made, so any + * changes to the list are reflected in the iterator. + * + * @author Michael Goodrich, Eric Zamore, Roberto Tamassia + */ +//begin#fragment Iterator +public class ElementIterator implements Iterator { + protected PositionList list; // the underlying list + protected Position cursor; // the next position + /** Creates an element iterator over the given list. */ + public ElementIterator(PositionList L) { + list = L; + cursor = (list.isEmpty())? null : list.first(); + } +//end#fragment Iterator + /** Returns whether the iterator has a next object. */ +//begin#fragment Iterator + public boolean hasNext() { return (cursor != null); } +//end#fragment Iterator + /** Returns the next object in the iterator. */ +//begin#fragment Iterator + public E next() throws NoSuchElementException { + if (cursor == null) + throw new NoSuchElementException("No next element"); + E toReturn = cursor.element(); + cursor = (cursor == list.last())? null : list.next(cursor); + return toReturn; + } +//end#fragment Iterator + /** Throws an {@link UnsupportedOperationException} in all cases, + * because removal is not a supported operation in this iterator. + */ + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException("remove"); + } +//begin#fragment Iterator +} +//end#fragment Iterator diff --git a/net/datastructures/EmptyDequeException.java b/net/datastructures/EmptyDequeException.java new file mode 100644 index 0000000..dff679d --- /dev/null +++ b/net/datastructures/EmptyDequeException.java @@ -0,0 +1,16 @@ +package net.datastructures; + +/** + * Runtime exception thrown when one tries to perform an access or + * removal operation on an empty deque. + * + * @author Natasha Gelfand + * @author Michael T. Goodrich + * @author Roberto Tamassia + */ + +public class EmptyDequeException extends RuntimeException { + public EmptyDequeException(String err) { + super(err); + } +} diff --git a/net/datastructures/EmptyListException.java b/net/datastructures/EmptyListException.java new file mode 100644 index 0000000..904f059 --- /dev/null +++ b/net/datastructures/EmptyListException.java @@ -0,0 +1,11 @@ +package net.datastructures; +/** + * Thrown when a list cannot fulfill the requested operation because + * it is empty. + * @author Roberto Tamassia + */ +public class EmptyListException extends RuntimeException { + public EmptyListException (String message) { + super (message); + } +} diff --git a/net/datastructures/EmptyPriorityQueueException.java b/net/datastructures/EmptyPriorityQueueException.java new file mode 100644 index 0000000..36a274d --- /dev/null +++ b/net/datastructures/EmptyPriorityQueueException.java @@ -0,0 +1,11 @@ +package net.datastructures; +/** + * Thrown when a priority queue cannot fulfill the requested operation + * because it is empty. + * @author Roberto Tamassia + */ +public class EmptyPriorityQueueException extends RuntimeException { + public EmptyPriorityQueueException (String message) { + super (message); + } +} diff --git a/net/datastructures/EmptyQueueException.java b/net/datastructures/EmptyQueueException.java new file mode 100644 index 0000000..f76e58f --- /dev/null +++ b/net/datastructures/EmptyQueueException.java @@ -0,0 +1,15 @@ +package net.datastructures; + +/** + * Runtime exception thrown when one tries to perform operation front + * or dequeue on an empty queue. + * @author Natasha Gelfand + * @author Michael T. Goodrich + * @author Roberto Tamassia + */ + +public class EmptyQueueException extends RuntimeException { + public EmptyQueueException(String err) { + super(err); + } +} diff --git a/net/datastructures/EmptyStackException.java b/net/datastructures/EmptyStackException.java new file mode 100644 index 0000000..0663df5 --- /dev/null +++ b/net/datastructures/EmptyStackException.java @@ -0,0 +1,16 @@ +package net.datastructures; +//begin#fragment EmptyStackException +/** + * Runtime exception thrown when one tries to perform operation top or + * pop on an empty stack. +//end#fragment EmptyStackException + * @author Roberto Tamassia +//begin#fragment EmptyStackException + */ + +public class EmptyStackException extends RuntimeException { + public EmptyStackException(String err) { + super(err); + } +} +//end#fragment EmptyStackException diff --git a/net/datastructures/EmptyTreeException.java b/net/datastructures/EmptyTreeException.java new file mode 100644 index 0000000..883d7ef --- /dev/null +++ b/net/datastructures/EmptyTreeException.java @@ -0,0 +1,11 @@ +package net.datastructures; +/** + * Runtime exception thrown when one tries to access the root of an + * empty tree. + */ + +public class EmptyTreeException extends RuntimeException { + public EmptyTreeException(String err) { + super(err); + } +} diff --git a/net/datastructures/Entry.java b/net/datastructures/Entry.java new file mode 100644 index 0000000..ea40851 --- /dev/null +++ b/net/datastructures/Entry.java @@ -0,0 +1,11 @@ +package net.datastructures; + +//begin#fragment Entry +/** Interface for a key-value pair entry **/ +public interface Entry { + /** Returns the key stored in this entry. */ + public K getKey(); + /** Returns the value stored in this entry. */ + public V getValue(); +} +//end#fragment Entry diff --git a/net/datastructures/EulerTour.java b/net/datastructures/EulerTour.java new file mode 100644 index 0000000..de8004d --- /dev/null +++ b/net/datastructures/EulerTour.java @@ -0,0 +1,49 @@ +package net.datastructures; +import net.datastructures.Position; +import net.datastructures.BinaryTree; + +//begin#fragment EulerTour +/** + * Template for algorithms traversing a binary tree using an Euler + * tour. The subclasses of this class will redefine some of the + * methods of this class to create a specific traversal. + */ +public abstract class EulerTour { + protected BinaryTree tree; + /** Execution of the traversal. This abstract method must be + * specified in a concrete subclass. */ + public abstract R execute(BinaryTree T); + /** Initialization of the traversal */ + protected void init(BinaryTree T) { tree = T; } + /** Template method */ + protected R eulerTour(Position v) { + TourResult r = new TourResult(); + visitLeft(v, r); + if (tree.hasLeft(v)) + r.left = eulerTour(tree.left(v)); // recursive traversal + visitBelow(v, r); + if (tree.hasRight(v)) + r.right = eulerTour(tree.right(v)); // recursive traversal + visitRight(v, r); + return r.out; + } + // Auxiliary methods that can be redefined by subclasses: + /** Method called for the visit on the left */ + protected void visitLeft(Position v, TourResult r) {} + /** Method called for the visit on from below */ + protected void visitBelow(Position v, TourResult r) {} + /** Method called for the visit on the right */ + protected void visitRight(Position v, TourResult r) {} + +//end#fragment EulerTour + +//begin#fragment TourResult + public class TourResult { + public R left; + public R right; + public R out; + } +//end#fragment TourResult +//begin#fragment EulerTour +} +//end#fragment EulerTour diff --git a/net/datastructures/FindCycleDFS.java b/net/datastructures/FindCycleDFS.java new file mode 100644 index 0000000..84dcffb --- /dev/null +++ b/net/datastructures/FindCycleDFS.java @@ -0,0 +1,54 @@ +package net.datastructures; +import java.util.Iterator; +//begin#fragment FindCycleDFS +/** This class specializes DFS to find a cycle. */ +//end#fragment FindCycleDFS + /* @author Roberto Tamassia, Michael Goodrich, Eric Zamore + */ +//begin#fragment FindCycleDFS +public class FindCycleDFS + extends DFS> { + protected PositionList cycle; // sequence of edges of the cycle + protected boolean done; + protected Vertex cycleStart; +//end#fragment FindCycleDFS + /** + * Executes the DFS algorithm. + * @param info unused + * @return {@link Iterable} collection containing the vertices and + * edges of a cycle. + */ +//begin#fragment FindCycleDFS + public void setup() { + cycle = new NodePositionList(); + done = false; + } + protected void startVisit(Vertex v) { cycle.addLast(v); } + protected void finishVisit(Vertex v) { + cycle.remove(cycle.last()); // remove v from cycle + if (!cycle.isEmpty()) cycle.remove(cycle.last()); // remove edge into v from cycle + } + protected void traverseDiscovery(Edge e, Vertex from) { + cycle.addLast(e); + } + protected void traverseBack(Edge e, Vertex from) { + cycle.addLast(e); // back edge e creates a cycle + cycleStart = graph.opposite(from, e); + cycle.addLast(cycleStart); // first vertex completes the cycle + done = true; + } + protected boolean isDone() { return done; } + public Iterable finalResult(Iterable r) { + // remove the vertices and edges from start to cycleStart + if (!cycle.isEmpty()) { + for (Position p: cycle.positions()) { + if (p.element() == cycleStart) + break; + cycle.remove(p); // remove vertex from cycle + } + } + return cycle; // list of the vertices and edges of the cycle + } +} +//end#fragment FindCycleDFS + diff --git a/net/datastructures/FindPathDFS.java b/net/datastructures/FindPathDFS.java new file mode 100644 index 0000000..422a724 --- /dev/null +++ b/net/datastructures/FindPathDFS.java @@ -0,0 +1,38 @@ +package net.datastructures; + +//begin#fragment FindPathDFS +/** Class specializing DFS to find a path between a start vertex and a target + * vertex. It assumes the target vertex is passed as the info object to the + * execute method. It returns an iterable list of the vertices and edges + * comprising the path from start to info. The returned path is empty if + * info is unreachable from start. */ +public class FindPathDFS + extends DFS, Iterable> { + protected PositionList path; + protected boolean done; + /** Setup method to initialize the path. */ + public void setup() { + path = new NodePositionList(); + done = false; + } + protected void startVisit(Vertex v) { + path.addLast(v); // add vertex v to path + if (v == info) + done = true; + } + protected void finishVisit(Vertex v) { + path.remove(path.last()); // remove v from path + if(!path.isEmpty()) // if v is not the start vertex + path.remove(path.last()); // remove discovery edge into v from path + } + protected void traverseDiscovery(Edge e, Vertex from) { + path.addLast(e); // add edge e to the path + } + protected boolean isDone() { + return done; + } + public Iterable finalResult(Iterable r) { + return path; + } +} +//end#fragment FindPathDFS diff --git a/net/datastructures/FullStackException.java b/net/datastructures/FullStackException.java new file mode 100644 index 0000000..4c3ea5d --- /dev/null +++ b/net/datastructures/FullStackException.java @@ -0,0 +1,13 @@ +package net.datastructures; +//begin#fragment FullStackException +/** + * Runtime exception thrown when the capacity of the array used by an + * ArrayStack has been exceeded. + * @see ArrayStack + */ +public class FullStackException extends RuntimeException { + public FullStackException(String err) { + super(err); + } +} +//end#fragment FullStackException diff --git a/net/datastructures/Graph.java b/net/datastructures/Graph.java new file mode 100644 index 0000000..95b3bf7 --- /dev/null +++ b/net/datastructures/Graph.java @@ -0,0 +1,47 @@ +package net.datastructures; +import java.util.Iterator; +/** + * An interface for a graph. + * @author Roberto Tamassia + */ +//begin#fragment Graph +public interface Graph { + /** Returns the number of vertices of the graph */ + public int numVertices(); + /** Returns the number of edges of the graph */ + public int numEdges(); + /** Returns the vertices of the graph as an iterable collection */ + public Iterable> vertices(); + /** Returns the edges of the graph as an iterable collection */ + public Iterable> edges(); + /** Replaces the element of a given vertex with a new element and + returns the old element */ + public V replace(Vertex p, V o) throws InvalidPositionException; + /** Replaces the element of a given edge with a new element and + returns the old element */ + public E replace(Edge p, E o) throws InvalidPositionException; + /** Returns the edges incident on a vertex as an iterable collection */ + public Iterable> incidentEdges(Vertex v) + throws InvalidPositionException; + /** Returns the endvertices of a vertex as an array of length 2 */ + public Vertex[] endVertices(Edge e) throws InvalidPositionException; + /** Returns the other endvertex of an incident edge */ + public Vertex opposite(Vertex v, Edge e) + throws InvalidPositionException; + /** Tests whether two vertices are adjacent */ + public boolean areAdjacent(Vertex u, Vertex v) + throws InvalidPositionException; + /** Inserts and return a new vertex with a given element */ + public Vertex insertVertex(V o); + /** Inserts and return a new edge with a given element between two + vertices */ + public Edge insertEdge(Vertex u, Vertex v, E o) + throws InvalidPositionException; + /** Removes a vertex and all its incident edges and returns the + element stored at the removed vertex */ + public V removeVertex(Vertex v) throws InvalidPositionException; + /** Removes an edge and return its element */ + public E removeEdge(Edge e) throws InvalidPositionException; +} +//end#fragment Graph + diff --git a/net/datastructures/HashTableMap.java b/net/datastructures/HashTableMap.java new file mode 100644 index 0000000..13d1ad7 --- /dev/null +++ b/net/datastructures/HashTableMap.java @@ -0,0 +1,177 @@ +package net.datastructures; +import java.util.Iterator; + +//begin#fragment Header +/** A hash table with linear probing and the MAD hash function */ +//end#fragment Header +/** + * A hash table data structure that uses linear probing to handle + * collisions. The hash function uses the built-in hashCode method + * and the multiply-add-and-divide method. The load factor is alwyas + * kept less than or equal to 0.5. When the load factor reaches 0.5, + * the entries are rehashed into a new bucket array with twice the + * capacity. + * + * @author Roberto Tamassia, Michael Goodrich, Eric Zamore + */ +//begin#fragment Header +public class HashTableMap implements Map { +//end#fragment Header + /** Nested class for an entry in a hash table. */ +//begin#fragment Header + public static class HashEntry implements Entry { + protected K key; + protected V value; + public HashEntry(K k, V v) { key = k; value = v; } + public V getValue() { return value; } + public K getKey() { return key; } + public V setValue(V val) { + V oldValue = value; + value = val; + return oldValue; + } + public boolean equals(Object o) { + HashEntry ent; + try { ent = (HashEntry) o; } + catch (ClassCastException ex) { return false; } + return (ent.getKey() == key) && (ent.getValue() == value); + } +//end#fragment Header + /** Entry visualization. */ + public String toString() { + return "(" + key + "," + value + ")"; + } +//begin#fragment Header + } + protected Entry AVAILABLE = new HashEntry(null, null); + protected int n = 0; // number of entries in the dictionary + protected int prime, capacity; // prime factor and capacity of bucket array + protected Entry[] bucket;// bucket array + protected long scale, shift; // the shift and scaling factors +//end#fragment Header + /** Creates a hash table with prime factor 109345121 and capacity 1000. */ + public HashTableMap() { this(109345121,1000); } +//begin#fragment Header + /** Creates a hash table with prime factor 109345121 and given capacity. */ + public HashTableMap(int cap) { this(109345121, cap); } + /** Creates a hash table with the given prime factor and capacity. */ + public HashTableMap(int p, int cap) { + prime = p; + capacity = cap; + bucket = (Entry[]) new Entry[capacity]; // safe cast + java.util.Random rand = new java.util.Random(); + scale = rand.nextInt(prime-1) + 1; + shift = rand.nextInt(prime); + } + /** Determines whether a key is valid. */ + protected void checkKey(K k) { + if (k == null) throw new InvalidKeyException("Invalid key: null."); + } + /** Hash function applying MAD method to default hash code. */ + public int hashValue(K key) { + return (int) ((Math.abs(key.hashCode()*scale + shift) % prime) % capacity); + } +//end#fragment Header +//begin#fragment Linear + /** Returns the number of entries in the hash table. */ + public int size() { return n; } + /** Returns whether or not the table is empty. */ + public boolean isEmpty() { return (n == 0); } + /** Returns an iterable object containing all of the keys. */ + public Iterable keySet() { + PositionList keys = new NodePositionList(); + for (int i=0; i e = bucket[i]; + if ( e == null) { + if (avail < 0) + avail = i; // key is not in table + break; + } + if (key.equals(e.getKey())) // we have found our key + return i; // key found + if (e == AVAILABLE) { // bucket is deactivated + if (avail < 0) + avail = i; // remember that this slot is available + } + i = (i + 1) % capacity; // keep looking + } while (i != j); + return -(avail + 1); // first empty or available slot + } + /** Returns the value associated with a key. */ + public V get (K key) throws InvalidKeyException { + int i = findEntry(key); // helper method for finding a key + if (i < 0) return null; // there is no value for this key, so reutrn null + return bucket[i].getValue(); // return the found value in this case + } +//end#fragment Linear +//begin#fragment Linear2 + /** Put a key-value pair in the map, replacing previous one if it exists. */ + public V put (K key, V value) throws InvalidKeyException { + int i = findEntry(key); //find the appropriate spot for this entry + if (i >= 0) // this key has a previous value + return ((HashEntry) bucket[i]).setValue(value); // set new value + if (n >= capacity/2) { + rehash(); // rehash to keep the load factor <= 0.5 + i = findEntry(key); //find again the appropriate spot for this entry + } + bucket[-i-1] = new HashEntry(key, value); // convert to proper index + n++; + return null; // there was no previous value + } + /** Doubles the size of the hash table and rehashes all the entries. */ + protected void rehash() { + capacity = 2*capacity; + Entry[] old = bucket; + bucket = (Entry[]) new Entry[capacity]; // new bucket is twice as big + java.util.Random rand = new java.util.Random(); + scale = rand.nextInt(prime-1) + 1; // new hash scaling factor + shift = rand.nextInt(prime); // new hash shifting factor + for (int i=0; i e = old[i]; + if ((e != null) && (e != AVAILABLE)) { // a valid entry + int j = - 1 - findEntry(e.getKey()); + bucket[j] = e; + } + } + } + /** Removes the key-value pair with a specified key. */ + public V remove (K key) throws InvalidKeyException { + int i = findEntry(key); // find this key first + if (i < 0) return null; // nothing to remove + V toReturn = bucket[i].getValue(); + bucket[i] = AVAILABLE; // mark this slot as deactivated + n--; + return toReturn; + } +//end#fragment Linear2 + /** Returns an iterable object containing all of the entries. */ + public Iterable> entrySet() { + PositionList> entries = new NodePositionList>(); + for (int i=0; i values() { + PositionList values = new NodePositionList(); + for (int i=0; i implements PriorityQueue { + protected CompleteBinaryTree> heap; // underlying heap + protected Comparator comp; // comparator for the keys + /** Inner class for heap entries. */ + protected static class MyEntry implements Entry { + protected K key; + protected V value; + public MyEntry(K k, V v) { key = k; value = v; } + public K getKey() { return key; } + public V getValue() { return value; } + public String toString() { return "(" + key + "," + value + ")"; } + } + /** Creates an empty heap with the default comparator */ + public HeapPriorityQueue() { + heap = new ArrayListCompleteBinaryTree>(); // use an array list + comp = new DefaultComparator(); // use the default comparator + } + /** Creates an empty heap with the given comparator */ + public HeapPriorityQueue(Comparator c) { + heap = new ArrayListCompleteBinaryTree>(); + comp = c; + } +//end#fragment HeapPriorityQueue + /** Sets the comparator used for comparing items in the heap. + * @throws IllegalStateException if priority queue is not empty */ + public void setComparator(Comparator c) throws IllegalStateException { + if(!isEmpty()) // this is only allowed if the priority queue is empty + throw new IllegalStateException("Priority queue is not empty"); + comp = c; + } +//begin#fragment HeapPriorityQueue + /** Returns the size of the heap */ + public int size() { return heap.size(); } + /** Returns whether the heap is empty */ + public boolean isEmpty() { return heap.size() == 0; } + //end#fragment HeapPriorityQueue + //begin#fragment mainMethods + /** Returns but does not remove an entry with minimum key */ + public Entry min() throws EmptyPriorityQueueException { + if (isEmpty()) + throw new EmptyPriorityQueueException("Priority queue is empty"); + return heap.root().element(); + } + /** Inserts a key-value pair and returns the entry created */ + public Entry insert(K k, V x) throws InvalidKeyException { + checkKey(k); // may throw an InvalidKeyException + Entry entry = new MyEntry(k,x); + upHeap(heap.add(entry)); + return entry; + } + /** Removes and returns an entry with minimum key */ + public Entry removeMin() throws EmptyPriorityQueueException { + if (isEmpty()) + throw new EmptyPriorityQueueException("Priority queue is empty"); + Entry min = heap.root().element(); + if (size() == 1) + heap.remove(); + else { + heap.replace(heap.root(), heap.remove()); + downHeap(heap.root()); + } + return min; + } + /** Determines whether a given key is valid */ + protected void checkKey(K key) throws InvalidKeyException { + try { + comp.compare(key,key); + } + catch(Exception e) { + throw new InvalidKeyException("Invalid key"); + } + } + //end#fragment mainMethods + //begin#fragment auxiliary + /** Performs up-heap bubbling */ + protected void upHeap(Position> v) { + Position> u; + while (!heap.isRoot(v)) { + u = heap.parent(v); + if (comp.compare(u.element().getKey(), v.element().getKey()) <= 0) break; + swap(u, v); + v = u; + } + } + /** Performs down-heap bubbling */ + protected void downHeap(Position> r) { + while (heap.isInternal(r)) { + Position> s; // the position of the smaller child + if (!heap.hasRight(r)) + s = heap.left(r); + else if (comp.compare(heap.left(r).element().getKey(), + heap.right(r).element().getKey()) <=0) + s = heap.left(r); + else + s = heap.right(r); + if (comp.compare(s.element().getKey(), r.element().getKey()) < 0) { + swap(r, s); + r = s; + } + else + break; + } + } + /** Swaps the entries of the two given positions */ + protected void swap(Position> x, Position> y) { + Entry temp = x.element(); + heap.replace(x, y.element()); + heap.replace(y, temp); + } + /** Text visualization for debugging purposes */ + public String toString() { + return heap.toString(); + } + //end#fragment auxiliary +} diff --git a/net/datastructures/IndexList.java b/net/datastructures/IndexList.java new file mode 100644 index 0000000..e1a8208 --- /dev/null +++ b/net/datastructures/IndexList.java @@ -0,0 +1,33 @@ +package net.datastructures; +import java.util.Iterator; +/** + * An interface for array lists. + * @author Roberto Tamassia, Michael Goodrich + */ +//begin#fragment Header +public interface IndexList { +//end#fragment Header +//begin#fragment Iterator + // ... the other List methods ... +//end#fragment Iterator +//begin#fragment List + /** Returns the number of elements in this list. */ + public int size(); + /** Returns whether the list is empty. */ + public boolean isEmpty(); + /** Inserts an element e to be at index i, shifting all elements after this. */ + public void add(int i, E e) + throws IndexOutOfBoundsException; + /** Returns the element at index i, without removing it. */ + public E get(int i) + throws IndexOutOfBoundsException; + /** Removes and returns the element at index i, shifting the elements after this. */ + public E remove(int i) + throws IndexOutOfBoundsException; + /** Replaces the element at index i with e, returning the previous element at i. */ + public E set(int i, E e) + throws IndexOutOfBoundsException; +//end#fragment List +//begin#fragment Tail +} +//end#fragment Tail diff --git a/net/datastructures/InvalidEntryException.java b/net/datastructures/InvalidEntryException.java new file mode 100644 index 0000000..155ff3b --- /dev/null +++ b/net/datastructures/InvalidEntryException.java @@ -0,0 +1,10 @@ +package net.datastructures; +/** + * Thrown when an entry is discovered to be invalid. + * @author Eric Zamore + */ +public class InvalidEntryException extends RuntimeException { + public InvalidEntryException (String message) { + super (message); + } +} diff --git a/net/datastructures/InvalidKeyException.java b/net/datastructures/InvalidKeyException.java new file mode 100644 index 0000000..a498c3c --- /dev/null +++ b/net/datastructures/InvalidKeyException.java @@ -0,0 +1,11 @@ +package net.datastructures; +/** + * Thrown when a key is determined to be invalid. + * @author Roberto Tamassia + */ +public class InvalidKeyException extends RuntimeException { + public InvalidKeyException (String message) { + super (message); + } + public static final long serialVersionUID = 424242L; +} diff --git a/net/datastructures/InvalidPositionException.java b/net/datastructures/InvalidPositionException.java new file mode 100644 index 0000000..a4515e2 --- /dev/null +++ b/net/datastructures/InvalidPositionException.java @@ -0,0 +1,18 @@ +package net.datastructures; +/** + * Thrown when a position is determined to be invalid. + * @author Roberto Tamassia, Michael Goodrich + */ +//begin#fragment InvalidPositionException +// A run-time exception for invalid positions +public class InvalidPositionException extends RuntimeException { + public InvalidPositionException(String err) { + super(err); + } +//end#fragment InvalidPositionException + public InvalidPositionException() { + /* default constructor */ + } +//begin#fragment InvalidPositionException +} +//end#fragment InvalidPositionException diff --git a/net/datastructures/LinkedBinaryTree.java b/net/datastructures/LinkedBinaryTree.java new file mode 100644 index 0000000..5998d96 --- /dev/null +++ b/net/datastructures/LinkedBinaryTree.java @@ -0,0 +1,314 @@ +package net.datastructures; +import java.util.Iterator; + +//begin#fragment LinkedBinaryTree +/** + * An implementation of the BinaryTree interface by means of a linked structure. +//end#fragment LinkedBinaryTree + * This class serves as a superclass for the BinarySearchTree + * implementation. This design decision was made to emphasize the + * conceptual relationship that a BinarySearchTree is a specialized + * LinkedBinaryTree. An unwanted side-effect of this is that the + * {@link #size() size} method returns the number of total nodes + * whereas the {@link BinarySearchTree#size() size} method in the + * {@link BinarySearchTree BinarySearchTree} class returns the number + * of internal nodes only. For this reason, the the {@link #size + * size} variable instead of the {@link #size() size} method is used + * within this class. + * + * @author Luca Vismara, Roberto Tamassia, Michael Goodrich, Eric + * Zamore + * @see BinaryTree +//begin#fragment LinkedBinaryTree + */ +public class LinkedBinaryTree implements BinaryTree { + protected BTPosition root; // reference to the root + protected int size; // number of nodes + /** Creates an empty binary tree. */ + public LinkedBinaryTree() { + root = null; // start with an empty tree + size = 0; + } + /** Returns the number of nodes in the tree. */ + public int size() { + return size; + } +//end#fragment LinkedBinaryTree + /** Returns whether the tree is empty. */ + public boolean isEmpty() { + return (size == 0); + } +//begin#fragment LinkedBinaryTree + /** Returns whether a node is internal. */ + public boolean isInternal(Position v) throws InvalidPositionException { + checkPosition(v); // auxiliary method + return (hasLeft(v) || hasRight(v)); + } +//end#fragment LinkedBinaryTree + /** Returns whether a node is external. */ + public boolean isExternal(Position v) throws InvalidPositionException { + return !isInternal(v); + } +//begin#fragment LinkedBinaryTree + /** Returns whether a node is the root. */ + public boolean isRoot(Position v) throws InvalidPositionException { + checkPosition(v); + return (v == root()); + } + /** Returns whether a node has a left child. */ + public boolean hasLeft(Position v) throws InvalidPositionException { + BTPosition vv = checkPosition(v); + return (vv.getLeft() != null); + } +//end#fragment LinkedBinaryTree + /** Returns whether a node has a right child. */ + public boolean hasRight(Position v) throws InvalidPositionException { + BTPosition vv = checkPosition(v); + return (vv.getRight() != null); + } +//begin#fragment LinkedBinaryTree + /** Returns the root of the tree. */ + public Position root() throws EmptyTreeException { + if (root == null) + throw new EmptyTreeException("The tree is empty"); + return root; + } + /** Returns the left child of a node. */ + 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; + } +//end#fragment LinkedBinaryTree + /** Returns the right child of a node. */ + 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; + } +//begin#fragment LinkedBinaryTree2 + /** Returns the parent of a node. */ + 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; + } + /** Returns an iterable collection of the children of a node. */ + 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; + } + /** Returns an iterable collection of the tree nodes. */ + public Iterable> positions() { + PositionList> positions = new NodePositionList>(); + if(size != 0) + preorderPositions(root(), positions); // assign positions in preorder + return positions; + } + /** Returns an iterator of the elements stored at the nodes */ + public Iterator iterator() { + Iterable> positions = positions(); + PositionList elements = new NodePositionList(); + for (Position pos: positions) + elements.addLast(pos.element()); + return elements.iterator(); // An iterator of elements + } + /** Replaces the element at a node. */ + public E replace(Position v, E o) + throws InvalidPositionException { + BTPosition vv = checkPosition(v); + E temp = v.element(); + vv.setElement(o); + return temp; + } +//end#fragment LinkedBinaryTree2 +//begin#fragment LinkedBinaryTree3 + // Additional accessor method + /** Return the sibling of a node */ + 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"); + } + // Additional update methods + /** Adds a root node to an empty tree */ + 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; + } + /** Inserts a left child at a given node. */ + 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; + } +//end#fragment LinkedBinaryTree3 + /** Inserts a right child at a given node. */ + 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; + } +//begin#fragment LinkedBinaryTree4 + /** Removes a node with zero or one child. */ + 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; // the only child of v, if any + if (leftPos != null) + ww = leftPos; + else if (rightPos != null) + ww = rightPos; + else // v is a leaf + ww = null; + if (vv == root) { // v is the root + if (ww != null) + ww.setParent(null); + root = ww; + } + else { // v is not the root + 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(); + } + +//end#fragment LinkedBinaryTree4 +//begin#fragment LinkedBinaryTree5 + /** 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); // T1 should be invalidated + } + if (!T2.isEmpty()) { + BTPosition r2 = checkPosition(T2.root()); + vv.setRight(r2); + r2.setParent(vv); // T2 should be invalidated + } + size = newSize; + } +//end#fragment LinkedBinaryTree5 + /** Swap the elements at two nodes */ + 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); + } + /** Expand an external node into an internal node with two external + node children */ + public void expandExternal(Position v, E l, E r) + throws InvalidPositionException { + if (!isExternal(v)) + throw new InvalidPositionException("Node is not external"); + insertLeft(v, l); + insertRight(v, r); + } + /** Remove an external node v and replace its parent with v's + sibling */ + public void removeAboveExternal(Position v) + throws InvalidPositionException { + if (!isExternal(v)) + throw new InvalidPositionException("Node is not external"); + if (isRoot(v)) + remove(v); + else { + Position u = parent(v); + remove(v); + remove(u); + } + } + // Auxiliary methods +//begin#fragment LinkedBinaryTree5 + /** If v is a good binary tree node, cast to BTPosition, else throw exception */ + protected BTPosition checkPosition(Position v) + throws InvalidPositionException { + if (v == null || !(v instanceof BTPosition)) + throw new InvalidPositionException("The position is invalid"); + return (BTPosition) v; + } + /** Creates a new binary tree node */ + protected BTPosition createNode(E element, BTPosition parent, + BTPosition left, BTPosition right) { + return new BTNode(element,parent,left,right); } + /** Creates a list storing the the nodes in the subtree of a node, + * ordered according to the preorder traversal of the subtree. */ + protected void preorderPositions(Position v, PositionList> pos) + throws InvalidPositionException { + pos.addLast(v); + if (hasLeft(v)) + preorderPositions(left(v), pos); // recurse on left child + if (hasRight(v)) + preorderPositions(right(v), pos); // recurse on right child + } +//end#fragment LinkedBinaryTree5 + /** Creates a list storing the the nodes in the subtree of a node, + * ordered according to the inorder traversal of the subtree. */ + protected void inorderPositions(Position v, PositionList> pos) + throws InvalidPositionException { + if (hasLeft(v)) + inorderPositions(left(v), pos); // recurse on left child + pos.addLast(v); + if (hasRight(v)) + inorderPositions(right(v), pos); // recurse on right child + } +} diff --git a/net/datastructures/LinkedTree.java b/net/datastructures/LinkedTree.java new file mode 100644 index 0000000..670bd8a --- /dev/null +++ b/net/datastructures/LinkedTree.java @@ -0,0 +1,138 @@ +package net.datastructures; +import java.util.Iterator; +import net.datastructures.*; + +//begin#fragment Tree +/** + * A linked class for a tree where nodes have an arbitrary number of children. +//end#fragment Tree + * @author Luca Vismara, Roberto Tamassia, Michael Goodrich, Eric Zamore +//begin#fragment Tree + */ +public class LinkedTree implements Tree { + protected TreePosition root; // reference to the root + protected int size; // number of nodes + /** Creates an empty tree. */ + public LinkedTree() { + root = null; // start with an empty tree + size = 0; + } + /** Returns the number of nodes in the tree. */ + public int size() { + return size; + } +//end#fragment LinkedTree + /** Returns whether the tree is empty. */ + public boolean isEmpty() { + return (size == 0); + } +//begin#fragment LinkedTree + /** Returns whether a node is internal. */ + public boolean isInternal(Position v) throws InvalidPositionException { + return !isExternal(v); + } +//end#fragment LinkedTree + /** Returns whether a node is external. */ + public boolean isExternal(Position v) throws InvalidPositionException { + TreePosition vv = checkPosition(v); // auxiliary method + return (vv.getChildren() == null) || vv.getChildren().isEmpty(); + } +//begin#fragment LinkedTree + /** Returns whether a node is the root. */ + public boolean isRoot(Position v) throws InvalidPositionException { + checkPosition(v); + return (v == root()); + } +//begin#fragment LinkedTree + /** Returns the root of the tree. */ + public Position root() throws EmptyTreeException { + if (root == null) + throw new EmptyTreeException("The tree is empty"); + return root; + } +//end#fragment LinkedTree +//begin#fragment LinkedTree2 + /** Returns the parent of a node. */ + public Position parent(Position v) + throws InvalidPositionException, BoundaryViolationException { + TreePosition vv = checkPosition(v); + Position parentPos = vv.getParent(); + if (parentPos == null) + throw new BoundaryViolationException("No parent"); + return parentPos; + } + /** Returns an iterable collection of the children of a node. */ + public Iterable> children(Position v) + throws InvalidPositionException { + TreePosition vv = checkPosition(v); + if (isExternal(v)) + throw new InvalidPositionException("External nodes have no children"); + return vv.getChildren(); + } + /** Returns an iterable collection of the tree nodes. */ + public Iterable> positions() { + PositionList> positions = new NodePositionList>(); + if(size != 0) + preorderPositions(root(), positions); // assign positions in preorder + return positions; + } + /** Returns an iterator of the elements stored at the nodes */ + public Iterator iterator() { + Iterable> positions = positions(); + PositionList elements = new NodePositionList(); + for (Position pos: positions) + elements.addLast(pos.element()); + return elements.iterator(); // An iterator of elements + } + /** Replaces the element at a node. */ + public E replace(Position v, E o) + throws InvalidPositionException { + TreePosition vv = checkPosition(v); + E temp = v.element(); + vv.setElement(o); + return temp; + } +//end#fragment LinkedTree2 +//begin#fragment LinkedTree3 + // Additional update methods + /** Adds a root node to an empty tree */ + public Position addRoot(E e) throws NonEmptyTreeException { + if(!isEmpty()) + throw new NonEmptyTreeException("Tree already has a root"); + size = 1; + root = createNode(e,null,null); + return root; + } + /** Swap the elements at two nodes */ + public void swapElements(Position v, Position w) + throws InvalidPositionException { + TreePosition vv = checkPosition(v); + TreePosition ww = checkPosition(w); + E temp = w.element(); + ww.setElement(v.element()); + vv.setElement(temp); + } + // Auxiliary methods +//begin#fragment LinkedTree5 + /** If v is a good tree node, cast to TreePosition, else throw exception */ + protected TreePosition checkPosition(Position v) + throws InvalidPositionException { + if (v == null || !(v instanceof TreePosition)) + throw new InvalidPositionException("The position is invalid"); + return (TreePosition) v; + } + /** Creates a new tree node */ + protected TreePosition createNode(E element, TreePosition parent, + PositionList> children) { + return new TreeNode(element,parent,children); + } + /** Creates a list storing the the nodes in the subtree of a node, + * ordered according to the preorder traversal of the subtree. */ + protected void preorderPositions(Position v, PositionList> pos) + throws InvalidPositionException { + pos.addLast(v); + for (Position w : children(v)) + preorderPositions(w, pos); // recurse on each child + } +} +//end#fragment LinkedTree5 diff --git a/net/datastructures/Map.java b/net/datastructures/Map.java new file mode 100644 index 0000000..43170cb --- /dev/null +++ b/net/datastructures/Map.java @@ -0,0 +1,36 @@ +package net.datastructures; +/** + * An interface for a map which binds a key uniquely to a value. + * @author Michael Goodrich + */ +//begin#fragment Map +// A simple Map interface +public interface Map { + /** Returns the number of items in the map. */ + public int size(); + /** Returns whether the map is empty. */ + public boolean isEmpty(); + /** + * If there is an entry with the specified key, replaces the value of + * this entry with the specified value and returns the old value. Else, + * adds a new entry with the specified key and value and returns null. + */ + public V put(K key, V value) throws InvalidKeyException; + /** + * Returns the value of the entry containing the given key. Returns + * null if no such entry exists. + */ + public V get(K key) throws InvalidKeyException; + /** + * If there is an entry with the specified key, removes this entry and + * returns its value. Else, returns null. + */ + public V remove(K key) throws InvalidKeyException; + /** Returns an iterable object containing all the keys in the map. */ + public Iterable keySet(); + /** Returns an iterable object containing all the values in the map. */ + public Iterable values(); + /** Returns an iterable object containing all the entries in the map. */ + public Iterable> entrySet(); +} +//end#fragment Map diff --git a/net/datastructures/Node.java b/net/datastructures/Node.java new file mode 100644 index 0000000..a8fb3c5 --- /dev/null +++ b/net/datastructures/Node.java @@ -0,0 +1,39 @@ +package net.datastructures; +/** + * Node of a singly linked list, which stores references to its + * element and to the next node in the list. + * + * @author Natasha Gelfand + * @author Roberto Tamassia + * @author Michael Goodrich + */ +//begin#fragment Node +public class Node { + // Instance variables: + private E element; + private Node next; + /** Creates a node with null references to its element and next node. */ + public Node() { + this(null, null); + } + /** Creates a node with the given element and next node. */ + public Node(E e, Node n) { + element = e; + next = n; + } + // Accessor methods: + public E getElement() { + return element; + } + public Node getNext() { + return next; + } + // Modifier methods: + public void setElement(E newElem) { + element = newElem; + } + public void setNext(Node newNext) { + next = newNext; + } +} +//end#fragment Node diff --git a/net/datastructures/NodeDeque.java b/net/datastructures/NodeDeque.java new file mode 100644 index 0000000..dc60a0e --- /dev/null +++ b/net/datastructures/NodeDeque.java @@ -0,0 +1,113 @@ +package net.datastructures; + /** + * Implementation of the Deque interface by means of a doubly linked + * list. This class uses class DLNode, which implements a node of + * the list. + * + * @author Natasha Gelfand + * @author Roberto Tamassia + */ + +//begin#fragment NodeDeque +public class NodeDeque implements Deque { + protected DLNode header, trailer; // sentinels + protected int size; // number of elements +//end#fragment NodeDeque + /** Creates an empty deque. */ +//begin#fragment NodeDeque + public NodeDeque() { // initialize an empty deque + header = new DLNode(); + trailer = new DLNode(); + header.setNext(trailer); // make header point to trailer + trailer.setPrev(header); // make trailer point to header + size = 0; + } + //end#fragment NodeDeque + +/** + * Return the size of the deque, that is the number of elements it has. + * @return Number of elements in the deque + */ + //begin#fragment size + public int size() { + return size; + } + //end#fragment size + +/** + * This function returns true if and only if the deque is empty + * @return true if the deque is empty, false otherwise + */ + //begin#fragment isEmpty + public boolean isEmpty() { + if (size == 0) + return true; + return false; + } + //end#fragment isEmpty + +/** + * Inspect the first element without modifying the deque. + * @return The first element in the sequence + */ + //begin#fragment first + public E getFirst() throws EmptyDequeException { + if (isEmpty()) + throw new EmptyDequeException("Deque is empty."); + return header.getNext().getElement(); + } + //end#fragment first + + public E getLast() throws EmptyDequeException { + if (isEmpty()) + throw new EmptyDequeException("Deque is empty."); + return trailer.getPrev().getElement(); + } + + //begin#fragment addFirst + public void addFirst(E o) { + DLNode second = header.getNext(); + DLNode first = new DLNode(o, header, second); + second.setPrev(first); + header.setNext(first); + size++; + } + //end#fragment addFirst + + public void addLast(E o) { + DLNode secondtolast = trailer.getPrev(); + DLNode last = new DLNode(o, secondtolast, trailer); + secondtolast.setNext(last); + trailer.setPrev(last); + size++; + } + + public E removeFirst() throws EmptyDequeException { + if (isEmpty()) + throw new EmptyDequeException("Deque is empty."); + DLNode first = header.getNext(); + E o = first.getElement(); + DLNode second = first.getNext(); + header.setNext(second); + second.setPrev(header); + size--; + return o; + } + + //begin#fragment removeLast + public E removeLast() throws EmptyDequeException { + if (isEmpty()) + throw new EmptyDequeException("Deque is empty."); + DLNode last = trailer.getPrev(); + E o = last.getElement(); + DLNode secondtolast = last.getPrev(); + trailer.setPrev(secondtolast); + secondtolast.setNext(trailer); + size--; + return o; + } + //end#fragment removeLast + +//begin#fragment tail +} +//end#fragment tail diff --git a/net/datastructures/NodePositionList.java b/net/datastructures/NodePositionList.java new file mode 100644 index 0000000..7d71d98 --- /dev/null +++ b/net/datastructures/NodePositionList.java @@ -0,0 +1,232 @@ +package net.datastructures; +import java.util.Iterator; +/** + * Realization of a PositionList using a doubly-linked list of nodes. + * + * @author Michael Goodrich, Natasha Gelfand, Roberto Tamassia, Eric Zamore + */ +//begin#fragment Header +public class NodePositionList implements PositionList { +//end#fragment Header +//begin#fragment Listvars + protected int numElts; // Number of elements in the list + protected DNode header, trailer; // Special sentinels +//end#fragment Listvars +//begin#fragment checkPosition + /** Constructor that creates an empty list; O(1) time */ + public NodePositionList() { + numElts = 0; + header = new DNode(null, null, null); // create header + trailer = new DNode(header, null, null); // create trailer + header.setNext(trailer); // make header and trailer point to each other + } + /** Checks if position is valid for this list and converts it to + * DNode if it is valid; O(1) time */ + protected DNode checkPosition(Position p) + throws InvalidPositionException { + if (p == null) + throw new InvalidPositionException + ("Null position passed to NodeList"); + if (p == header) + throw new InvalidPositionException + ("The header node is not a valid position"); + if (p == trailer) + throw new InvalidPositionException + ("The trailer node is not a valid position"); + try { + DNode temp = (DNode) p; + if ((temp.getPrev() == null) || (temp.getNext() == null)) + throw new InvalidPositionException + ("Position does not belong to a valid NodeList"); + return temp; + } catch (ClassCastException e) { + throw new InvalidPositionException + ("Position is of wrong type for this list"); + } + } + //end#fragment checkPosition + //begin#fragment first + /** Returns the number of elements in the list; O(1) time */ + public int size() { return numElts; } + /** Returns whether the list is empty; O(1) time */ + public boolean isEmpty() { return (numElts == 0); } + /** Returns the first position in the list; O(1) time */ + public Position first() + throws EmptyListException { + if (isEmpty()) + throw new EmptyListException("List is empty"); + return header.getNext(); + } + //end#fragment first + /** Returns the last position in the list; O(1) time */ + public Position last() + throws EmptyListException { + if (isEmpty()) + throw new EmptyListException("List is empty"); + return trailer.getPrev(); + } + //begin#fragment first + /** Returns the position before the given one; O(1) time */ + public Position prev(Position p) + throws InvalidPositionException, BoundaryViolationException { + DNode v = checkPosition(p); + DNode prev = v.getPrev(); + if (prev == header) + throw new BoundaryViolationException + ("Cannot advance past the beginning of the list"); + return prev; + } + //end#fragment first + /** Returns the position after the given one; O(1) time */ + public Position next(Position p) + throws InvalidPositionException, BoundaryViolationException { + DNode v = checkPosition(p); + DNode next = v.getNext(); + if (next == trailer) + throw new BoundaryViolationException + ("Cannot advance past the end of the list"); + return next; + } + //begin#fragment first + /** Insert the given element before the given position; + * O(1) time */ + public void addBefore(Position p, E element) + throws InvalidPositionException { + DNode v = checkPosition(p); + numElts++; + DNode newNode = new DNode(v.getPrev(), v, element); + v.getPrev().setNext(newNode); + v.setPrev(newNode); + } + //end#fragment first + /** Insert the given element after the given position; + * O(1) time */ + public void addAfter(Position p, E element) + throws InvalidPositionException { + DNode v = checkPosition(p); + numElts++; + DNode newNode = new DNode(v, v.getNext(), element); + v.getNext().setPrev(newNode); + v.setNext(newNode); + } + //begin#fragment remove + /** Insert the given element at the beginning of the list, returning + * the new position; O(1) time */ + public void addFirst(E element) { + numElts++; + DNode newNode = new DNode(header, header.getNext(), element); + header.getNext().setPrev(newNode); + header.setNext(newNode); + } + //end#fragment remove + /** Insert the given element at the end of the list, returning + * the new position; O(1) time */ + public void addLast(E element) { + numElts++; + DNode oldLast = trailer.getPrev(); + DNode newNode = new DNode(oldLast, trailer, element); + oldLast.setNext(newNode); + trailer.setPrev(newNode); + } + //begin#fragment remove + /**Remove the given position from the list; O(1) time */ + public E remove(Position p) + throws InvalidPositionException { + DNode v = checkPosition(p); + numElts--; + DNode vPrev = v.getPrev(); + DNode vNext = v.getNext(); + vPrev.setNext(vNext); + vNext.setPrev(vPrev); + E vElem = v.element(); + // unlink the position from the list and make it invalid + v.setNext(null); + v.setPrev(null); + return vElem; + } + /** Replace the element at the given position with the new element + * and return the old element; O(1) time */ + public E set(Position p, E element) + throws InvalidPositionException { + DNode v = checkPosition(p); + E oldElt = v.element(); + v.setElement(element); + return oldElt; + } + //end#fragment remove + +//begin#fragment Iterator + /** Returns an iterator of all the elements in the list. */ + public Iterator iterator() { return new ElementIterator(this); } +//end#fragment Iterator +//begin#fragment PIterator + /** Returns an iterable collection of all the nodes in the list. */ + public Iterable> positions() { // create a list of posiitons + PositionList> P = new NodePositionList>(); + if (!isEmpty()) { + Position p = first(); + while (true) { + P.addLast(p); // add position p as the last element of list P + if (p == last()) + break; + p = next(p); + } + } + return P; // return P as our Iterable object + } +//end#fragment PIterator + + // Convenience methods + /** Returns whether a position is the first one; O(1) time */ + public boolean isFirst(Position p) + throws InvalidPositionException { + DNode v = checkPosition(p); + return v.getPrev() == header; + } + /** Returns whether a position is the last one; O(1) time */ + public boolean isLast(Position p) + throws InvalidPositionException { + DNode v = checkPosition(p); + return v.getNext() == trailer; + } + /** Swap the elements of two give positions; O(1) time */ + public void swapElements(Position a, Position b) + throws InvalidPositionException { + DNode pA = checkPosition(a); + DNode pB = checkPosition(b); + E temp = pA.element(); + pA.setElement(pB.element()); + pB.setElement(temp); + } + /** Returns a textual representation of a given node list using for-each */ + public static String forEachToString(PositionList L) { + String s = "["; + int i = L.size(); + for (E elem: L) { + s += elem; // implicit cast of the element to String + i--; + if (i > 0) + s += ", "; // separate elements with a comma + } + s += "]"; + return s; + } +//begin#fragment toString + /** Returns a textual representation of a given node list */ + public static String toString(PositionList l) { + Iterator it = l.iterator(); + String s = "["; + while (it.hasNext()) { + s += it.next(); // implicit cast of the next element to String + if (it.hasNext()) + s += ", "; + } + s += "]"; + return s; + } +//end#fragment toString + /** Returns a textual representation of the list */ + public String toString() { + return toString(this); + } +} diff --git a/net/datastructures/NodeQueue.java b/net/datastructures/NodeQueue.java new file mode 100644 index 0000000..d820a82 --- /dev/null +++ b/net/datastructures/NodeQueue.java @@ -0,0 +1,128 @@ +package net.datastructures; + +/** + * Realization of a queue by means of a singly-linked list of nodes. + * All operations are performed in constant time. + * + * @author Roberto Tamassia + */ + +public class NodeQueue implements Queue { + + protected Node head, tail; // the head and tail nodes + protected int size; // Keeps track of number of elements in queue + + /** Creates an empty queue. */ + public NodeQueue() { + head = null; + tail = null; + size = 0; + } + + public int size() { //# Return the current queue size + return size; + } + + public boolean isEmpty() { //# Returns true iff queue is empty + if ( (head==null) && (tail==null) ) + return true; + return false; + } + + //begin#fragment enqueue + public void enqueue(E elem) { + Node node = new Node(); + node.setElement(elem); + node.setNext(null); // node will be new tail node + if (size == 0) + head = node; // special case of a previously empty queue + else + tail.setNext(node); // add node at the tail of the list + tail = node; // update the reference to the tail node + size++; + } + //end#fragment enqueue + + public E front() //# Return the first queue element + throws EmptyQueueException { + if (size == 0) + throw new EmptyQueueException("Queue is empty."); + return head.getElement(); + } + + //begin#fragment dequeue + public E dequeue() throws EmptyQueueException { + if (size == 0) + throw new EmptyQueueException("Queue is empty."); + E tmp = head.getElement(); + head = head.getNext(); + size--; + if (size == 0) + tail = null; // the queue is now empty + return tmp; + } + //end#fragment dequeue + + public String toString() { + String s = ""; + s += "("; + if (!isEmpty()) { + Node p = head; + do { + s += p.getElement() ; + if (p != tail) + s += ", "; + p = p.getNext(); + } while (p != null); + } + s += ")"; + return s; + } + + /** + * Prints information about an operation and the queue. + * @param op operation performed + * @param element element returned by the operation + * @return information about the operation performed, the element + * returned by the operation and the content of the stack after + * the operation. + */ + public static void status(Queue Q, String op, Object element) { + System.out.println("---------------------------------"); + System.out.println(op); + System.out.println("Returned: " + element); + String emptyStatus; + if (Q.isEmpty()) + emptyStatus = "empty"; + else + emptyStatus = "not empty"; + System.out.println("size = " + Q.size() + ", " + emptyStatus); + System.out.println("Queue: " + Q); + } + + /** + * Test program that performs a series of operations on on a queue and + * prints the operation performed, the returned element and the + * content of the stack after each operation. + */ + public static void main(String[] args) { + Object o; + Queue A = new NodeQueue(); + status (A, "New empty queue", null); + A.enqueue(5); + status (A, "enqueue(5)", null); + A.enqueue(3); + status (A, "enqueue(3)", null); + A.enqueue(7); + status (A, "enqueue(7)", null); + o = A.dequeue(); + status (A, "dequeue()", o); + A.enqueue(9); + status (A, "enqueue(9)", null); + o = A.dequeue(); + status (A, "dequeue()", o); + o = o = A.front(); + status (A, "front()", o); + } + +} diff --git a/net/datastructures/NodeStack.java b/net/datastructures/NodeStack.java new file mode 100644 index 0000000..92784f0 --- /dev/null +++ b/net/datastructures/NodeStack.java @@ -0,0 +1,116 @@ +package net.datastructures; +/** + * Implementation of the stack ADT by means of a singly linked list. + * + * @author Natasha Gelfand + * @author Roberto Tamassia + * @see Node + */ + +//begin#fragment NodeStack +public class NodeStack implements Stack { + protected Node top; // reference to the head node + protected int size; // number of elements in the stack +//end#fragment NodeStack + /** Creates an empty stack. */ +//begin#fragment NodeStack + public NodeStack() { // constructs an empty stack + top = null; + size = 0; + } + public int size() { return size; } + public boolean isEmpty() { + if (top == null) return true; + return false; + } + public void push(E elem) { + Node v = new Node(elem, top); // create and link-in a new node + top = v; + size++; + } + public E top() throws EmptyStackException { + if (isEmpty()) throw new EmptyStackException("Stack is empty."); + return top.getElement(); + } + public E pop() throws EmptyStackException { + if (isEmpty()) throw new EmptyStackException("Stack is empty."); + E temp = top.getElement(); + top = top.getNext(); // link-out the former top node + size--; + return temp; + } +//end#fragment NodeStack + + + /** + * Returns a string representation of the stack as a list of elements, + * with the top element at the end: [ ... , prev, top ]. + * This method runs in O(n) time, where n is the size of the stack. + * @return textual representation of the stack. + */ + public String toString() { + String s; + Node cur = null; + s = "["; + int n = size(); + if (n > 0) { + cur = top; + s += cur.getElement(); + } + if (n > 1) + for (int i = 1; i <= n-1; i++) { + cur = cur.getNext(); + s += ", " + cur.getElement(); + } + s += "]"; + return s; + } + + /** + * Prints information about an operation and the stack. + * @param op operation performed + * @param element element returned by the operation + * @return information about the operation performed, the element + * returned by the operation and the content of the stack after + * the operation. + */ + public static void status(Stack S, String op, Object element) { + System.out.println("---------------------------------"); + System.out.println(op); + System.out.println("Returned: " + element); + String emptyStatus; + if (S.isEmpty()) + emptyStatus = "empty"; + else + emptyStatus = "not empty"; + System.out.println("size = " + S.size() + ", " + emptyStatus); + System.out.println("Stack: " + S); + } + + /** + * Test program that performs a series of operations on on a stack and + * prints the operation performed, the returned element and the + * content of the stack after each operation. + */ + public static void main(String[] args) { + Object o; + Stack A = new NodeStack(); + status (A, "New empty stack", null); + A.push(5); + status (A, "push(5)", null); + A.push(3); + status (A, "push(3)", null); + A.push(7); + status (A, "push(7)", null); + o = A.pop(); + status (A, "pop()", o); + A.push(9); + status (A, "push(9)", null); + o = A.pop(); + status (A, "pop()", o); + o = o = A.top(); + status (A, "top()", o); + } +//begin#fragment NodeStack +} +//end#fragment NodeStack diff --git a/net/datastructures/NonEmptyTreeException.java b/net/datastructures/NonEmptyTreeException.java new file mode 100644 index 0000000..8e90ae5 --- /dev/null +++ b/net/datastructures/NonEmptyTreeException.java @@ -0,0 +1,11 @@ +package net.datastructures; +/** + * Runtime exception thrown when one tries to create the root of a + * tree that is not empty. + */ + +public class NonEmptyTreeException extends RuntimeException { + public NonEmptyTreeException(String err) { + super(err); + } +} diff --git a/net/datastructures/Position.java b/net/datastructures/Position.java new file mode 100644 index 0000000..8754d5b --- /dev/null +++ b/net/datastructures/Position.java @@ -0,0 +1,12 @@ +package net.datastructures; +/** + * An interface for a position, which is a holder object storing a + * single element. + * @author Roberto Tamassia, Michael Goodrich + */ +//begin#fragment All +public interface Position { + /** Return the element stored at this position. */ + E element(); +} +//end#fragment All diff --git a/net/datastructures/PositionList.java b/net/datastructures/PositionList.java new file mode 100644 index 0000000..3b13905 --- /dev/null +++ b/net/datastructures/PositionList.java @@ -0,0 +1,50 @@ +package net.datastructures; +import java.util.Iterator; +/** + * An interface for positional lists. + * @author Roberto Tamassia, Michael Goodrich + */ +//begin#fragment Header +public interface PositionList extends Iterable { +//end#fragment Header +//begin#fragment List + /** Returns the number of elements in this list. */ + public int size(); + /** Returns whether the list is empty. */ + public boolean isEmpty(); + /** Returns the first node in the list. */ + public Position first(); + /** Returns the last node in the list. */ + public Position last(); + /** Returns the node after a given node in the list. */ + public Position next(Position p) + throws InvalidPositionException, BoundaryViolationException; + /** Returns the node before a given node in the list. */ + public Position prev(Position p) + throws InvalidPositionException, BoundaryViolationException; + /** Inserts an element at the front of the list, returning new position. */ + public void addFirst(E e); + /** Inserts and element at the back of the list, returning new position. */ + public void addLast(E e); + /** Inserts an element after the given node in the list. */ + public void addAfter(Position p, E e) + throws InvalidPositionException; + /** Inserts an element before the given node in the list. */ + public void addBefore(Position p, E e) + throws InvalidPositionException; + /** Removes a node from the list, returning the element stored there. */ + public E remove(Position p) throws InvalidPositionException; + /** Replaces the element stored at the given node, returning old element. */ + public E set(Position p, E e) throws InvalidPositionException; +//end#fragment List +//begin#fragment Positions + /** Returns an iterable collection of all the nodes in the list. */ + public Iterable> positions(); +//end#fragment Positions +//begin#fragment Iterator + /** Returns an iterator of all the elements in the list. */ + public Iterator iterator(); +//end#fragment Iterator +//begin#fragment Tail +} +//end#fragment Tail diff --git a/net/datastructures/PriorityQueue.java b/net/datastructures/PriorityQueue.java new file mode 100644 index 0000000..0376251 --- /dev/null +++ b/net/datastructures/PriorityQueue.java @@ -0,0 +1,17 @@ +package net.datastructures; + +//begin#fragment PriorityQueue +/** Interface for the priority queue ADT */ +public interface PriorityQueue { + /** Returns the number of items in the priority queue. */ + public int size(); + /** Returns whether the priority queue is empty. */ + public boolean isEmpty(); + /** Returns but does not remove an entry with minimum key. */ + public Entry min() throws EmptyPriorityQueueException; + /** Inserts a key-value pair and return the entry created. */ + public Entry insert(K key, V value) throws InvalidKeyException; + /** Removes and returns an entry with minimum key. */ + public Entry removeMin() throws EmptyPriorityQueueException; +} +//end#fragment PriorityQueue diff --git a/net/datastructures/Queue.java b/net/datastructures/Queue.java new file mode 100644 index 0000000..2bc959c --- /dev/null +++ b/net/datastructures/Queue.java @@ -0,0 +1,43 @@ + package net.datastructures; +/** + * Interface for a queue: a collection of elements that are inserted + * and removed according to the first-in first-out principle. + * + * @author Michael T. Goodrich + * @author Natasha Gelfand + * @author Mark Handy + * @author Roberto Tamassia + * @see EmptyQueueException + */ + +//begin#fragment Queue +public interface Queue { + /** + * Returns the number of elements in the queue. + * @return number of elements in the queue. + */ + public int size(); + /** + * Returns whether the queue is empty. + * @return true if the queue is empty, false otherwise. + */ + public boolean isEmpty(); + /** + * Inspects the element at the front of the queue. + * @return element at the front of the queue. + * @exception EmptyQueueException if the queue is empty. + */ + public E front() throws EmptyQueueException; + /** + * Inserts an element at the rear of the queue. + * @param element new element to be inserted. + */ + public void enqueue (E element); + /** + * Removes the element at the front of the queue. + * @return element removed. + * @exception EmptyQueueException if the queue is empty. + */ + public E dequeue() throws EmptyQueueException; +} +//end#fragment Queue diff --git a/net/datastructures/RBTree.java b/net/datastructures/RBTree.java new file mode 100644 index 0000000..d40d6f0 --- /dev/null +++ b/net/datastructures/RBTree.java @@ -0,0 +1,219 @@ + + +package net.datastructures; +import java.util.Comparator; + +/** + * Realization of a red-black Tree by extending a binary search tree. + * + * @author Michael Goodrich, Roberto Tamassia, Eric Zamore + */ + +//begin#fragment RBTree +/** Realization of a dictionary by means of a red-black tree. */ +public class RBTree + extends BinarySearchTree implements Dictionary { + public RBTree() { super(); } + public RBTree(Comparator C) { super(C); } + /** Nested class for the nodes of a red-black tree */ + protected static class RBNode extends BTNode> { + protected boolean isRed; // we add a color field to a BTNode + RBNode() {/* default constructor */} + /** Preferred constructor */ + RBNode(Entry element, BTPosition> parent, + BTPosition> left, BTPosition> right) { + super(element, parent, left, right); + isRed = false; + } + public boolean isRed() {return isRed;} + public void makeRed() {isRed = true;} + public void makeBlack() {isRed = false;} + public void setColor(boolean color) {isRed = color;} + } + //end#fragment RBTree + //begin#fragment insertItem + /** Creates a new tree node. */ + protected BTPosition> createNode(Entry element, + BTPosition> parent, BTPosition> left, + BTPosition> right) { + return new RBNode(element,parent,left,right); // a red-black node + } + //end#fragment insertItem + /** Inserts an item into the dictionary and returns the newly + * created entry. */ + //begin#fragment insertItem + public Entry insert(K k, V x) throws InvalidKeyException { + Entry toReturn = super.insert(k, x); + Position> posZ = actionPos; // start at the insertion position + setRed(posZ); + if (isRoot(posZ)) + setBlack(posZ); + else + remedyDoubleRed(posZ); // fix a double-red color violation + return toReturn; + } + //end#fragment insertItem + /** Remedies a double red violation at a given node caused by insertion. */ + //begin#fragment insertItem + protected void remedyDoubleRed(Position> posZ) { + Position> posV = parent(posZ); + if (isRoot(posV)) + return; + if (!isPosRed(posV)) + return; + // we have a double red: posZ and posV + if (!isPosRed(sibling(posV))) { // Case 1: trinode restructuring + posV = restructure(posZ); + setBlack(posV); + setRed(left(posV)); + setRed(right(posV)); + } + else { // Case 2: recoloring + setBlack(posV); + setBlack(sibling(posV)); + Position> posU = parent(posV); + if (isRoot(posU)) + return; + setRed(posU); + remedyDoubleRed(posU); + } + } + //end#fragment insertItem + /** Removes and returns the given entry from the dictionary. */ + //begin#fragment remedyDoubleBlack + public Entry remove(Entry ent) throws InvalidEntryException { + Entry toReturn = super.remove(ent); + Position> posR = actionPos; + if (toReturn != null) { + if (wasParentRed(posR) || isRoot(posR) || isPosRed(posR)) + setBlack(posR); + else + remedyDoubleBlack(posR); + } + return toReturn; + } + //end#fragment remedyDoubleBlack + /** Remedies a double black violation at a given node caused by removal. */ + //begin#fragment remedyDoubleBlack + protected void remedyDoubleBlack(Position> posR) { + Position> posX, posY, posZ; + boolean oldColor; + posX = parent(posR); + posY = sibling(posR); + if (!isPosRed(posY)) { + posZ = redChild(posY); + if (hasRedChild(posY)) { // Case 1: trinode restructuring + oldColor = isPosRed(posX); + posZ = restructure(posZ); + setColor(posZ, oldColor); + setBlack(posR); + setBlack(left(posZ)); + setBlack(right(posZ)); + return; + } + setBlack(posR); + setRed(posY); + if (!isPosRed(posX)) { // Case 2: recoloring + if (!isRoot(posX)) + remedyDoubleBlack(posX); + return; + } + setBlack(posX); + return; + } // Case 3: adjustment + if (posY == right(posX)) posZ = right(posY); + else posZ = left(posY); + restructure(posZ); + setBlack(posY); + setRed(posX); + remedyDoubleBlack(posR); + } + //end#fragment remedyDoubleBlack + + /** Returns whether a node is red. */ + protected boolean isPosRed(Position> position) { + return ((RBNode) position).isRed(); + } + + /** Returns whether the former parent of a node was red. */ + private boolean wasParentRed(Position> position){ + if (!isRoot(position)) { + if(!isPosRed(position) && !isPosRed(parent(position))) { + if (isExternal(sibling(position)) || + (hasTwoExternalChildren(sibling(position)) && + isPosRed(sibling(position)))) + return true; //then position's old parent was red + } + } + return false; + } + + /** Returns whether an internal node has two external children. */ + private boolean hasTwoExternalChildren(Position> position){ + if (isExternal(left(position)) + && isExternal(right(position))) + return true; + else + return false; + } + + /** Colors a node red. */ + protected void setRed(Position> position) { + ((RBNode) position).makeRed(); + } + + /** Colors a node black. */ + protected void setBlack(Position> position) { + ((RBNode) position).makeBlack(); + } + + /** Sets the color of a node. + * @param color true to color the node red, false + * to color the node black*/ + protected void setColor(Position> position, boolean color) { + ((RBNode) position).setColor(color); + } + + /** Returns a red child of a node. */ + protected Position> redChild(Position> position) { + Position> child = left(position); + if (isPosRed(child)) + return child; + child = right(position); + if (isPosRed(child)) + return child; + return null; + } + + /** Returns whether a node has a red child. */ + protected boolean hasRedChild(Position> position){ + if (isPosRed(left(position)) || isPosRed(right(position))) + return true; + else + return false; + } + + /** + * Swaps the colors of a and b if they are + * different and returns whether a was red. + */ + protected boolean swapColor(Position> a, Position> b){ + boolean wasRed = false; + if (isPosRed(a) && !isPosRed(b)){ + wasRed = true; + setBlack(a); + setRed(b); + } + else if (!isPosRed(a) && isPosRed(b)){ + setBlack(b); + setRed(a); + } + return wasRed; + } + + /** Swaps the colors and elements at the two nodes. */ + protected void swap(Position> swapPos, Position> remPos){ + swapColor(remPos, swapPos); + swapElements(swapPos, remPos); + } +} diff --git a/net/datastructures/RBTreeMap.java b/net/datastructures/RBTreeMap.java new file mode 100644 index 0000000..0fc3422 --- /dev/null +++ b/net/datastructures/RBTreeMap.java @@ -0,0 +1,225 @@ +package net.datastructures; +import java.util.Comparator; + +/** + * Realization of a red-black tree by extending a binary search tree. + * + * @author Michael Goodrich, Roberto Tamassia, Eric Zamore + */ + +//begin#fragment RBTree +/** Realization of a map by means of a red-black tree. */ +public class RBTreeMap + extends BinarySearchTreeMap implements Map { + public RBTreeMap() { super(); } + public RBTreeMap(Comparator C) { super(C); } + /** Nested class for the nodes of a red-black tree */ + protected static class RBNode extends BTNode> { + protected boolean isRed; // we add a color field to a BTNode + RBNode() {/* default constructor */} + /** Preferred constructor */ + RBNode(Entry element, BTPosition> parent, + BTPosition> left, BTPosition> right) { + super(element, parent, left, right); + isRed = false; + } + public boolean isRed() {return isRed;} + public void makeRed() {isRed = true;} + public void makeBlack() {isRed = false;} + public void setColor(boolean color) {isRed = color;} + } + //end#fragment RBTree + //begin#fragment insertItem + /** Creates a new tree node. */ + protected BTPosition> createNode(Entry element, + BTPosition> parent, BTPosition> left, + BTPosition> right) { + return new RBNode(element,parent,left,right); // a red-black node + } + //end#fragment insertItem + /** + * If there is an entry with the specified key, replaces the value of + * this entry with the specified value and returns the old value. Else, + * adds a new entry with the specified key and value and returns null. + */ + //begin#fragment insertItem + public V put(K k, V x) throws InvalidKeyException { + V toReturn = super.put(k, x); + Position> posZ = actionPos; + if (toReturn == null) { // a new entry has been added + setRed(posZ); + if (isRoot(posZ)) + setBlack(posZ); + else + remedyDoubleRed(posZ); // fix a double-red color violation + } + return toReturn; + } + //end#fragment insertItem + /** Remedies a double red violation at a given node caused by insertion. */ + //begin#fragment insertItem + protected void remedyDoubleRed(Position> posZ) { + Position> posV = parent(posZ); + if (isRoot(posV)) + return; + if (!isPosRed(posV)) + return; + // we have a double red: posZ and posV + if (!isPosRed(sibling(posV))) { // Case 1: trinode restructuring + posV = restructure(posZ); + setBlack(posV); + setRed(left(posV)); + setRed(right(posV)); + } + else { // Case 2: recoloring + setBlack(posV); + setBlack(sibling(posV)); + Position> posU = parent(posV); + if (isRoot(posU)) + return; + setRed(posU); + remedyDoubleRed(posU); + } + } + //end#fragment insertItem + /** + * If there is an entry with the specified key, removes this entry and + * returns its value. Else, returns null. + */ + //begin#fragment remedyDoubleBlack + public V remove(K k) throws InvalidKeyException { + V toReturn = super.remove(k); + Position> posR = actionPos; + if (toReturn != null) { + if (wasParentRed(posR) || isRoot(posR) || isPosRed(posR)) + setBlack(posR); + else + remedyDoubleBlack(posR); + } + return toReturn; + } + //end#fragment remedyDoubleBlack + /** Remedies a double black violation at a given node caused by removal. */ + //begin#fragment remedyDoubleBlack + protected void remedyDoubleBlack(Position> posR) { + Position> posX, posY, posZ; + boolean oldColor; + posX = parent(posR); + posY = sibling(posR); + if (!isPosRed(posY)) { + posZ = redChild(posY); + if (hasRedChild(posY)) { // Case 1: trinode restructuring + oldColor = isPosRed(posX); + posZ = restructure(posZ); + setColor(posZ, oldColor); + setBlack(posR); + setBlack(left(posZ)); + setBlack(right(posZ)); + return; + } + setBlack(posR); + setRed(posY); + if (!isPosRed(posX)) { // Case 2: recoloring + if (!isRoot(posX)) + remedyDoubleBlack(posX); + return; + } + setBlack(posX); + return; + } // Case 3: adjustment + if (posY == right(posX)) posZ = right(posY); + else posZ = left(posY); + restructure(posZ); + setBlack(posY); + setRed(posX); + remedyDoubleBlack(posR); + } + //end#fragment remedyDoubleBlack + + /** Returns whether a node is red. */ + protected boolean isPosRed(Position> position) { + return ((RBNode) position).isRed(); + } + + /** Returns whether the former parent of a node was red. */ + private boolean wasParentRed(Position> position){ + if (!isRoot(position)) { + if(!isPosRed(position) && !isPosRed(parent(position))) { + if (isExternal(sibling(position)) || + (hasTwoExternalChildren(sibling(position)) && + isPosRed(sibling(position)))) + return true; //then position's old parent was red + } + } + return false; + } + + /** Returns whether an internal node has two external children. */ + private boolean hasTwoExternalChildren(Position> position){ + if (isExternal(left(position)) + && isExternal(right(position))) + return true; + else + return false; + } + + /** Colors a node red. */ + protected void setRed(Position> position) { + ((RBNode) position).makeRed(); + } + + /** Colors a node black. */ + protected void setBlack(Position> position) { + ((RBNode) position).makeBlack(); + } + + /** Sets the color of a node. + * @param color true to color the node red, false + * to color the node black*/ + protected void setColor(Position> position, boolean color) { + ((RBNode) position).setColor(color); + } + + /** Returns a red child of a node. */ + protected Position> redChild(Position> position) { + Position> child = left(position); + if (isPosRed(child)) + return child; + child = right(position); + if (isPosRed(child)) + return child; + return null; + } + + /** Returns whether a node has a red child. */ + protected boolean hasRedChild(Position> position){ + if (isPosRed(left(position)) || isPosRed(right(position))) + return true; + else + return false; + } + + /** + * Swaps the colors of a and b if they are + * different and returns whether a was red. + */ + protected boolean swapColor(Position> a, Position> b){ + boolean wasRed = false; + if (isPosRed(a) && !isPosRed(b)){ + wasRed = true; + setBlack(a); + setRed(b); + } + else if (!isPosRed(a) && isPosRed(b)){ + setBlack(b); + setRed(a); + } + return wasRed; + } + + /** Swaps the colors and elements at the two nodes. */ + protected void swap(Position> swapPos, Position> remPos){ + swapColor(remPos, swapPos); + swapElements(swapPos, remPos); + } +} diff --git a/net/datastructures/Sequence.java b/net/datastructures/Sequence.java new file mode 100644 index 0000000..b623e9d --- /dev/null +++ b/net/datastructures/Sequence.java @@ -0,0 +1,17 @@ +package net.datastructures; +//begin#fragment Sequence +/** + * An interface for a sequence, a data structure supporting all + * operations of a deque, indexed list and position list. +//end#fragment Sequence + * @author Roberto Tamassia, Michael Goodrich +//begin#fragment Sequence + */ +public interface Sequence + extends Deque, IndexList, PositionList { + /** Returns the position containing the element at the given index. */ + public Position atIndex(int r) throws BoundaryViolationException; + /** Returns the index of the element stored at the given position. */ + public int indexOf(Position p) throws InvalidPositionException; +} +//end#fragment Sequence diff --git a/net/datastructures/Sort.java b/net/datastructures/Sort.java new file mode 100644 index 0000000..3788001 --- /dev/null +++ b/net/datastructures/Sort.java @@ -0,0 +1,254 @@ +package net.datastructures; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.util.Comparator; +import java.util.Random; +import java.util.Arrays; +/** + * Class containing various sorting algorithms. + * + * @author Michael Goodrich, Roberto Tamassia, Eric Zamore + */ +public class Sort { + //begin#fragment mergeSort + /** + * Sorts the elements of list in in nondecreasing order according + * to comparator c, using the merge-sort algorithm. + **/ + public static void mergeSort (PositionList in, Comparator c) { + int n = in.size(); + if (n < 2) + return; // the in list is already sorted in this case + // divide + PositionList in1 = new NodePositionList(); + PositionList in2 = new NodePositionList(); + int i = 0; + while (i < n/2) { + in1.addLast(in.remove(in.first())); // move the first n/2 elements to in1 + i++; + } + while (!in.isEmpty()) + in2.addLast(in.remove(in.first())); // move the rest to in2 + // recur + mergeSort(in1,c); + mergeSort(in2,c); + //conquer + merge(in1,in2,c,in); + } + //end#fragment mergeSort + + //begin#fragment merge + /** + * Merges two sorted lists, in1 and in2, into a sorted list in. + **/ + public static void merge(PositionList in1, PositionList in2, + Comparator c, PositionList in) { + while (!in1.isEmpty() && !in2.isEmpty()) + if (c.compare(in1.first().element(), in2.first().element()) <= 0) + in.addLast(in1.remove(in1.first())); + else + in.addLast(in2.remove(in2.first())); + while(!in1.isEmpty()) // move the remaining elements of in1 + in.addLast(in1.remove(in1.first())); + while(!in2.isEmpty()) // move the remaining elements of in2 + in.addLast(in2.remove(in2.first())); + } + //end#fragment merge + + //begin#fragment mergeSort2 + /** Sorts an array with a comparator using nonrecursive merge sort. */ + public static void mergeSort(E[] orig, Comparator c) { + E[] in = (E[]) new Object[orig.length]; // make a new temporary array + System.arraycopy(orig,0,in,0,in.length); // copy the input + E[] out = (E[]) new Object[in.length]; // output array + E[] temp; // temp array reference used for swapping + int n = in.length; + for (int i=1; i < n; i*=2) { // each iteration sorts all length-2*i runs + for (int j=0; j < n; j+=2*i) // each iteration merges two length-i pairs + merge(in,out,c,j,i); // merge from in to out two length-i runs at j + temp = in; in = out; out = temp; // swap arrays for next iteration + } + // the "in" array contains the sorted array, so re-copy it + System.arraycopy(in,0,orig,0,in.length); + } + /** Merges two subarrays, specified by a start and increment. */ + protected static void merge(E[] in, E[] out, Comparator c, int start, + int inc) { // merge in[start..start+inc-1] and in[start+inc..start+2*inc-1] + int x = start; // index into run #1 + int end1 = Math.min(start+inc, in.length); // boundary for run #1 + int end2 = Math.min(start+2*inc, in.length); // boundary for run #2 + int y = start+inc; // index into run #2 (could be beyond array boundary) + int z = start; // index into the out array + while ((x < end1) && (y < end2)) + if (c.compare(in[x],in[y]) <= 0) out[z++] = in[x++]; + else out[z++] = in[y++]; + if (x < end1) // first run didn't finish + System.arraycopy(in, x, out, z, end1 - x); + else if (y < end2) // second run didn't finish + System.arraycopy(in, y, out, z, end2 - y); + } + //end#fragment mergeSort2 + + /** + * Sorts the elements of list in in nondecreasing order according to + * comparator c, using a list-based implementation of the deterministic + * quicksort algorithm. + **/ + public static void quickSort(PositionList in, Comparator c) { + if (in.size() <= 1) + return; + E pivot = in.remove(in.last()); + PositionList lesser = new NodePositionList(); + PositionList equal = new NodePositionList(); + PositionList greater = new NodePositionList(); + E cur; + while (!in.isEmpty()) { + cur = in.remove(in.first()); + if (c.compare(cur,pivot) < 0) + lesser.addFirst(cur); + else if(c.compare(cur,pivot) == 0) + equal.addFirst(cur); + else + greater.addFirst(cur); + } + quickSort(lesser,c); // recur on lesser list + quickSort(greater,c); // recur on greater list + while(!lesser.isEmpty()) + in.addLast(lesser.remove(lesser.first())); + while(!equal.isEmpty()) + in.addLast(equal.remove(equal.first())); + in.addLast(pivot); + while(!greater.isEmpty()) + in.addLast(greater.remove(greater.first())); + } + + + /** + * Sorts the elements of array s in nondecreasing order according + * to comparator c, using the quick-sort algorithm. Most of the work + * is done by the auxiliary recursive method quickSortStep. + **/ + //begin#fragment quickSort + public static void quickSort (E[] s, Comparator c) { + if (s.length < 2) return; // the array is already sorted in this case + quickSortStep(s, c, 0, s.length-1); // recursive sort method + } + //end#fragment quickSort + + /** + * Sorts in nondecreasing order the elements of sequence s between + * ranks leftBound and rightBound, using a recursive, in-place, + * implementation of the quick-sort algorithm. + **/ + //begin#fragment quickSortStep + private static void quickSortStep (E[] s, Comparator c, + int leftBound, int rightBound ) { + if (leftBound >= rightBound) return; // the indices have crossed + E temp; // temp object used for swapping + E pivot = s[rightBound]; + int leftInd = leftBound; // will scan rightward + int rightInd = rightBound-1; // will scan leftward + while (leftInd <= rightInd) { // scan right until larger than the pivot + while ( (leftInd <= rightInd) && (c.compare(s[leftInd], pivot)<=0) ) + leftInd++; + while ( (rightInd >= leftInd) && (c.compare(s[rightInd], pivot)>=0)) + rightInd--; + if (leftInd < rightInd) { // both elements were found, so swap + temp = s[rightInd]; s[rightInd] = s[leftInd]; s[leftInd] = temp; + } + } // the loop continues until the indices cross + temp = s[rightBound]; // swap pivot with element at leftInd + s[rightBound] = s[leftInd]; + s[leftInd] = temp; // the pivot is now at leftInd + quickSortStep(s, c, leftBound, leftInd-1); // left recursive call + quickSortStep(s, c, leftInd+1, rightBound); // right recursive call + } + //end#fragment quickSortStep + + public static void main (String[] argv) throws IOException { + out("Start your engines..."); + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + Random r = new Random(); + Comparator c = new DefaultComparator(); + out("Enter number of elements:"); + String num = in.readLine(); + int n = (new Integer(num)).intValue(); + String cont; + Integer[] A = new Integer[n]; + Integer[] B = new Integer[n]; + float msin=0f,qsin=0f,msout=0f,qsout=0f; + long t; + do { + PositionList C = new NodePositionList(); + PositionList D = new NodePositionList(); + for (int i = 0; i < n; i++) { + int x = r.nextInt(100); + A[i] = new Integer(x); + B[i] = new Integer(x); + C.addLast(new Integer(x)); + D.addLast(new Integer(x)); + } + out("Array-Based Sorting"); + out("Before: " + Arrays.asList(A)); + + //array-based mergesort + t = System.currentTimeMillis(); + mergeSort(A, c); + msin = (System.currentTimeMillis()-t)/1000f; + out("MSort: " + Arrays.asList(A)); + + String correct = Arrays.asList(A).toString(); + + //array-based quicksort + t = System.currentTimeMillis(); + quickSort(B, c); + qsin = (System.currentTimeMillis()-t)/1000f; + out("QSort: " + Arrays.asList(B)); + + if(!correct.equals(Arrays.asList(B).toString())) { + System.out.println("sorts produced different results!"); + System.exit(1); + } + + out("List-Based Sorting"); + + //list-based mergesort + t = System.currentTimeMillis(); + mergeSort(C, c); + out("MSort: " + C); + msout = (System.currentTimeMillis()-t)/1000f; + + if(!correct.equals(C.toString())) { + System.out.println("sorts produced different results!"); + System.exit(1); + } + + //list-based quicksort + t = System.currentTimeMillis(); + quickSort(D, c); + out("QSort: " + D); + qsout = (System.currentTimeMillis()-t)/1000f; + + if(!correct.equals(D.toString())) { + System.out.println("sorts produced different results!"); + System.exit(1); + } + + out("Times (in seconds)"); + out("Array-Based"); + out("MSort: "+msin); + out("QSort: "+qsin); + out("List-Based"); + out("MSort: "+msout); + out("QSort: "+qsout); + + out("Type 'e' to end ..."); + cont = in.readLine(); + } while (cont.equals("")); + } + + private static void out (String s) { + System.out.println(s); + } +} diff --git a/net/datastructures/SortedListPriorityQueue.java b/net/datastructures/SortedListPriorityQueue.java new file mode 100644 index 0000000..26d9219 --- /dev/null +++ b/net/datastructures/SortedListPriorityQueue.java @@ -0,0 +1,117 @@ +package net.datastructures; +import java.util.Comparator; +/** + * Realization of a priority queue by means of a sorted node list in + * nondecreasing order. + * @author Roberto Tamassia, Michael Goodrich, Eric Zamore + */ +//begin#fragment SortedListPriorityQueue1 +public class SortedListPriorityQueue implements PriorityQueue { + protected PositionList> entries; + protected Comparator c; + protected Position> actionPos; // variable used by subclasses + /** Inner class for entries */ + protected static class MyEntry implements Entry { + protected K k; // key + protected V v; // value + public MyEntry(K key, V value) { + k = key; + v = value; + } + // methods of the Entry interface + public K getKey() { return k; } + public V getValue() { return v; } +//end#fragment SortedListPriorityQueue1 + // overrides toString, useful for debugging + public String toString() { return "(" + k + "," + v + ")"; } +//begin#fragment SortedListPriorityQueue1 + } + /** Creates the priority queue with the default comparator. */ + public SortedListPriorityQueue () { + entries = new NodePositionList>(); + c = new DefaultComparator(); + } + /** Creates the priority queue with the given comparator. */ + public SortedListPriorityQueue (Comparator comp) { + entries = new NodePositionList>(); + c = comp; + } + //end#fragment SortedListPriorityQueue1 + /** Creates the priority queue with the given comparator and list. + * The list is assumed to be sorted in nondecreasing order.*/ + public SortedListPriorityQueue (PositionList> list, Comparator comp) { + entries = list; + c = comp; + } + /** Sets the comparator for this priority queue. + * @throws IllegalStateException if priority queue is not empty */ + public void setComparator(Comparator comp) throws IllegalStateException { + if(!isEmpty()) // this is only allowed if the priority queue is empty + throw new IllegalStateException("Priority queue is not empty"); + c = comp; + } + /** Returns the number of elements in the priority queue. */ + public int size () {return entries.size(); } + /** Returns whether the priority queue is empty. */ + public boolean isEmpty () { return entries.isEmpty(); } + //begin#fragment SortedListPriorityQueue2 + /** Returns but does not remove an entry with minimum key. */ + public Entry min () throws EmptyPriorityQueueException { + if (entries.isEmpty()) + throw new EmptyPriorityQueueException("priority queue is empty"); + else + return entries.first().element(); + } + /** Inserts a key-value pair and return the entry created. */ + public Entry insert (K k, V v) throws InvalidKeyException { + checkKey(k); // auxiliary key-checking method (could throw exception) + Entry entry = new MyEntry(k, v); + insertEntry(entry); // auxiliary insertion method + return entry; + } + /** Auxiliary method used for insertion. */ + protected void insertEntry(Entry e) { + if (entries.isEmpty()) { + entries.addFirst(e); // insert into empty list + actionPos = entries.first(); // insertion position + } + else if (c.compare(e.getKey(), entries.last().element().getKey()) > 0) { + entries.addLast(e); // insert at the end of the list + actionPos = entries.last(); // insertion position + } + else { + Position> curr = entries.first(); + while (c.compare(e.getKey(), curr.element().getKey())> 0) { + curr = entries.next(curr); // advance toward insertion position + } + entries.addBefore(curr, e); + actionPos = entries.prev(curr); // insertion position + } + } + /** Removes and returns an entry with minimum key. */ + public Entry removeMin() throws EmptyPriorityQueueException { + if (entries.isEmpty()) + throw new EmptyPriorityQueueException("priority queue is empty"); + else + return entries.remove(entries.first()); + } +//end#fragment SortedListPriorityQueue2 + +//begin#fragment SortedListPriorityQueue3 + /** Determines whether a key is valid. */ + protected boolean checkKey(K key) throws InvalidKeyException { + boolean result; + try { // check if the key can be compared to itself + result = (c.compare(key,key)==0); + } catch (ClassCastException e) + { throw new InvalidKeyException("key cannot be compared"); } + return result; + } + // overrides toString, useful for debugging + public String toString() { + return entries.toString(); + } +//end#fragment SortedListPriorityQueue3 +//begin#fragment tail +} +//end#fragment tail diff --git a/net/datastructures/Stack.java b/net/datastructures/Stack.java new file mode 100644 index 0000000..e442b90 --- /dev/null +++ b/net/datastructures/Stack.java @@ -0,0 +1,44 @@ +package net.datastructures; +//begin#fragment Stack + /** + * Interface for a stack: a collection of objects that are inserted + * and removed according to the last-in first-out principle. This + * interface includes the main methods of java.util.Stack. + * + * @author Roberto Tamassia + * @author Michael Goodrich + * @see EmptyStackException + */ + +public interface Stack { + /** + * Return the number of elements in the stack. + * @return number of elements in the stack. + */ + public int size(); + /** + * Return whether the stack is empty. + * @return true if the stack is empty, false otherwise. + */ + public boolean isEmpty(); + /** + * Inspect the element at the top of the stack. + * @return top element in the stack. + * @exception EmptyStackException if the stack is empty. + */ + public E top() + throws EmptyStackException; + /** + * Insert an element at the top of the stack. + * @param element to be inserted. + */ + public void push (E element); + /** + * Remove the top element from the stack. + * @return element removed. + * @exception EmptyStackException if the stack is empty. + */ + public E pop() + throws EmptyStackException; +} +//end#fragment Stack diff --git a/net/datastructures/Tree.java b/net/datastructures/Tree.java new file mode 100644 index 0000000..4ef6b7f --- /dev/null +++ b/net/datastructures/Tree.java @@ -0,0 +1,41 @@ +package net.datastructures; +import java.util.Iterator; + +//begin#fragment Tree +/** + * An interface for a tree where nodes can have an arbitrary number of children. +//end#fragment Tree + * @author Michael Goodrich +//begin#fragment Tree + */ +public interface Tree { + /** Returns the number of nodes in the tree. */ + public int size(); + /** Returns whether the tree is empty. */ + public boolean isEmpty(); + /** Returns an iterator of the elements stored in the tree. */ + public Iterator iterator(); + /** Returns an iterable collection of the the nodes. */ + public Iterable> positions(); + /** Replaces the element stored at a given node. */ + public E replace(Position v, E e) + throws InvalidPositionException; + /** Returns the root of the tree. */ + public Position root() throws EmptyTreeException; + /** Returns the parent of a given node. */ + public Position parent(Position v) + throws InvalidPositionException, BoundaryViolationException; + /** Returns an iterable collection of the children of a given node. */ + public Iterable> children(Position v) + throws InvalidPositionException; + /** Returns whether a given node is internal. */ + public boolean isInternal(Position v) + throws InvalidPositionException; + /** Returns whether a given node is external. */ + public boolean isExternal(Position v) + throws InvalidPositionException; + /** Returns whether a given node is the root of the tree. */ + public boolean isRoot(Position v) + throws InvalidPositionException; +} +//end#fragment Tree diff --git a/net/datastructures/TreeNode.java b/net/datastructures/TreeNode.java new file mode 100644 index 0000000..d930ca0 --- /dev/null +++ b/net/datastructures/TreeNode.java @@ -0,0 +1,39 @@ +package net.datastructures; +//begin#fragment TNode +/** + * Class implementing a node of a binary tree by storing references to + * an element, a parent node, a left node, and a right node. +//end#fragment TNode + * + * @author Luca Vismara, Roberto Tamassia, Michael Goodrich +//begin#fragment TNode + */ +public class TreeNode implements TreePosition { + private E element; // element stored at this node + private TreePosition parent; // adjacent node + private PositionList> children; // children nodes +//end#fragment TNode + /** Default constructor */ + public TreeNode() { } +//begin#fragment TNode + /** Main constructor */ + public TreeNode(E element, TreePosition parent, + PositionList> children) { + setElement(element); + setParent(parent); + setChildren(children); + } + /** Returns the element stored at this position */ + public E element() { return element; } + /** Sets the element stored at this position */ + public void setElement(E o) { element=o; } + /** Returns the children of this position */ + public PositionList> getChildren() { return children; } + /** Sets the right child of this position */ + public void setChildren(PositionList> c) { children=c; } + /** Returns the parent of this position */ + public TreePosition getParent() { return parent; } + /** Sets the parent of this position */ + public void setParent(TreePosition v) { parent=v; } +} +//end#fragment TNode diff --git a/net/datastructures/TreePosition.java b/net/datastructures/TreePosition.java new file mode 100644 index 0000000..0b72c68 --- /dev/null +++ b/net/datastructures/TreePosition.java @@ -0,0 +1,18 @@ +package net.datastructures; +//begin#fragment TPos +/** + * Interface for a node of a binary tree. It maintains an element, a + * parent node, a left node, and a right node. +//end#fragment TPos + * + * @author Michael Goodrich +//begin#fragment TPos + */ +public interface TreePosition extends Position { // inherits element() + public void setElement(E o); + public PositionList> getChildren(); + public void setChildren(PositionList> c); + public TreePosition getParent(); + public void setParent(TreePosition v); +} +//end#fragment TPos diff --git a/net/datastructures/Vertex.java b/net/datastructures/Vertex.java new file mode 100644 index 0000000..63ed4f2 --- /dev/null +++ b/net/datastructures/Vertex.java @@ -0,0 +1,6 @@ +package net.datastructures; +/** + * An interface for a vertex of a graph. + * @author Roberto Tamassia + */ +public interface Vertex extends DecorablePosition { }