data_structures_free
This commit is contained in:
115
net/datastructures/AVLTree.java
Normal file
115
net/datastructures/AVLTree.java
Normal file
@@ -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<K,V>
|
||||
extends BinarySearchTree<K,V> implements Dictionary<K,V> {
|
||||
public AVLTree(Comparator<K> c) { super(c); }
|
||||
public AVLTree() { super(); }
|
||||
/** Nested class for the nodes of an AVL tree. */
|
||||
protected static class AVLNode<K,V> extends BTNode<Entry<K,V>> {
|
||||
protected int height; // we add a height field to a BTNode
|
||||
AVLNode() {/* default constructor */}
|
||||
/** Preferred constructor */
|
||||
AVLNode(Entry<K,V> element, BTPosition<Entry<K,V>> parent,
|
||||
BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> right) {
|
||||
super(element, parent, left, right);
|
||||
height = 0;
|
||||
if (left != null)
|
||||
height = Math.max(height, 1 + ((AVLNode<K,V>) left).getHeight());
|
||||
if (right != null)
|
||||
height = Math.max(height, 1 + ((AVLNode<K,V>) 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<Entry<K,V>> createNode(Entry<K,V> element,
|
||||
BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left,
|
||||
BTPosition<Entry<K,V>> right) {
|
||||
return new AVLNode<K,V>(element,parent,left,right); // now use AVL nodes
|
||||
}
|
||||
/** Returns the height of a node (call back to an AVLNode). */
|
||||
protected int height(Position<Entry<K,V>> p) {
|
||||
return ((AVLNode<K,V>) p).getHeight();
|
||||
}
|
||||
/** Sets the height of an internal node (call back to an AVLNode). */
|
||||
protected void setHeight(Position<Entry<K,V>> p) {
|
||||
((AVLNode<K,V>) 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<Entry<K,V>> 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<Entry<K,V>> tallerChild(Position<Entry<K,V>> 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<Entry<K,V>> 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<Entry<K,V>> 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<K,V> insert(K k, V v) throws InvalidKeyException {
|
||||
Entry<K,V> 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<K,V> remove(Entry<K,V> ent) throws InvalidEntryException {
|
||||
Entry<K,V> 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
|
||||
119
net/datastructures/AVLTreeMap.java
Normal file
119
net/datastructures/AVLTreeMap.java
Normal file
@@ -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<K,V>
|
||||
extends BinarySearchTreeMap<K,V> implements Map<K,V> {
|
||||
public AVLTreeMap(Comparator<K> c) { super(c); }
|
||||
public AVLTreeMap() { super(); }
|
||||
/** Nested class for the nodes of an AVL tree. */
|
||||
protected static class AVLNode<K,V> extends BTNode<Entry<K,V>> {
|
||||
protected int height; // we add a height field to a BTNode
|
||||
AVLNode() {/* default constructor */}
|
||||
/** Preferred constructor */
|
||||
AVLNode(Entry<K,V> element, BTPosition<Entry<K,V>> parent,
|
||||
BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> right) {
|
||||
super(element, parent, left, right);
|
||||
height = 0;
|
||||
if (left != null)
|
||||
height = Math.max(height, 1 + ((AVLNode<K,V>) left).getHeight());
|
||||
if (right != null)
|
||||
height = Math.max(height, 1 + ((AVLNode<K,V>) 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<Entry<K,V>> createNode(Entry<K,V> element,
|
||||
BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left,
|
||||
BTPosition<Entry<K,V>> right) {
|
||||
return new AVLNode<K,V>(element,parent,left,right); // now use AVL nodes
|
||||
}
|
||||
/** Returns the height of a node (call back to an AVLNode). */
|
||||
protected int height(Position<Entry<K,V>> p) {
|
||||
return ((AVLNode<K,V>) p).getHeight();
|
||||
}
|
||||
/** Sets the height of an internal node (call back to an AVLNode). */
|
||||
protected void setHeight(Position<Entry<K,V>> p) {
|
||||
((AVLNode<K,V>) 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<Entry<K,V>> 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<Entry<K,V>> tallerChild(Position<Entry<K,V>> 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<Entry<K,V>> 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<Entry<K,V>> 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
|
||||
75
net/datastructures/ArrayIndexList.java
Normal file
75
net/datastructures/ArrayIndexList.java
Normal file
@@ -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<E> implements IndexList<E> {
|
||||
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<size; i++)
|
||||
B[i] = A[i];
|
||||
A = B;
|
||||
}
|
||||
for (int i=size-1; 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<size-1; i++) // shift elements down
|
||||
A[i] = A[i+1];
|
||||
size--;
|
||||
return temp;
|
||||
}
|
||||
//end#fragment vector
|
||||
/** Checks whether the given index is in the range [0, n - 1] */
|
||||
protected void checkIndex(int r, int n) //
|
||||
throws IndexOutOfBoundsException { //
|
||||
if (r < 0 || r >= n)
|
||||
throw new IndexOutOfBoundsException("Illegal index: " + r);
|
||||
}
|
||||
}
|
||||
192
net/datastructures/ArrayListCompleteBinaryTree.java
Normal file
192
net/datastructures/ArrayListCompleteBinaryTree.java
Normal file
@@ -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 <code>n</code> has rank <i>i</i>,
|
||||
* then the left child of <code>n</code> will have rank 2*<i>i</i>,
|
||||
* and the right child of <code>n</code> will have rank 2*<i>i</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<E>
|
||||
implements CompleteBinaryTree<E> {
|
||||
protected ArrayList<BTPos<E>> T; // indexed list of tree positions
|
||||
/** Nested class for a index list-based complete binary tree node. */
|
||||
protected static class BTPos<E> implements Position<E> {
|
||||
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<BTPos<E>>();
|
||||
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<E> 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<E> v) throws InvalidPositionException {
|
||||
return !isInternal(v);
|
||||
}
|
||||
/** Returns whether v is the root node. */
|
||||
public boolean isRoot(Position<E> v) throws InvalidPositionException {
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return vv.index() == 1;
|
||||
}
|
||||
/** Returns whether v has a left child. */
|
||||
public boolean hasLeft(Position<E> v) throws InvalidPositionException {
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return 2*vv.index() <= size();
|
||||
}
|
||||
/** Returns whether v has a right child. */
|
||||
public boolean hasRight(Position<E> v) throws InvalidPositionException {
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return 2*vv.index() + 1 <= size();
|
||||
}
|
||||
/** Returns the root of the tree. */
|
||||
public Position<E> root() throws EmptyTreeException {
|
||||
if (isEmpty()) throw new EmptyTreeException("Tree is empty");
|
||||
return T.get(1);
|
||||
}
|
||||
/** Returns the left child of v. */
|
||||
public Position<E> left(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
if (!hasLeft(v)) throw new BoundaryViolationException("No left child");
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return T.get(2*vv.index());
|
||||
}
|
||||
/** Returns the right child of v. */
|
||||
public Position<E> right(Position<E> v)
|
||||
throws InvalidPositionException {
|
||||
if (!hasRight(v)) throw new BoundaryViolationException("No right child");
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return T.get(2*vv.index() + 1);
|
||||
}
|
||||
//end#fragment VectorHeap2
|
||||
//begin#fragment VectorHeap3
|
||||
/** Returns the parent of v. */
|
||||
public Position<E> parent(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
if (isRoot(v)) throw new BoundaryViolationException("No parent");
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return T.get(vv.index()/2);
|
||||
}
|
||||
//end#fragment VectorHeap3
|
||||
/** Returns an iterable collection of the children of v. */
|
||||
public Iterable<Position<E>> children(Position<E> v) throws InvalidPositionException {
|
||||
PositionList<Position<E>> children = new NodePositionList<Position<E>>();
|
||||
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<Position<E>> positions() {
|
||||
ArrayList<Position<E>> P = new ArrayList<Position<E>>();
|
||||
Iterator<BTPos<E>> 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<E> v, E o) throws InvalidPositionException {
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
return vv.setElement(o);
|
||||
}
|
||||
/** Adds an element just after the last node (in a level numbering). */
|
||||
public Position<E> add(E e) {
|
||||
int i = size() + 1;
|
||||
BTPos<E> p = new BTPos<E>(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<E> checkPosition(Position<E> v)
|
||||
throws InvalidPositionException
|
||||
{
|
||||
if (v == null || !(v instanceof BTPos))
|
||||
throw new InvalidPositionException("Position is invalid");
|
||||
return (BTPos<E>) v;
|
||||
}
|
||||
//end#fragment VectorHeap3
|
||||
// Additional Methods
|
||||
/** Returns the sibling of v. */
|
||||
public Position<E> sibling(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
try {
|
||||
Position<E> p = parent(v);
|
||||
Position<E> 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<E> v, Position<E> w)
|
||||
throws InvalidPositionException {
|
||||
BTPos<E> vv = checkPosition(v);
|
||||
BTPos<E> 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<E> iterator() {
|
||||
ArrayList<E> list = new ArrayList<E>();
|
||||
Iterator<BTPos<E>> 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
|
||||
189
net/datastructures/ArrayStack.java
Normal file
189
net/datastructures/ArrayStack.java
Normal file
@@ -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<E> implements Stack<E> {
|
||||
//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<Integer> A = new ArrayStack<Integer>();
|
||||
A.status("new ArrayStack<Integer> 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<String> B = new ArrayStack<String>();
|
||||
B.status("new ArrayStack<String> 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
|
||||
43
net/datastructures/BTNode.java
Normal file
43
net/datastructures/BTNode.java
Normal file
@@ -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<E> implements BTPosition<E> {
|
||||
private E element; // element stored at this node
|
||||
private BTPosition<E> left, right, parent; // adjacent nodes
|
||||
//end#fragment BTNode
|
||||
/** Default constructor */
|
||||
public BTNode() { }
|
||||
//begin#fragment BTNode
|
||||
/** Main constructor */
|
||||
public BTNode(E element, BTPosition<E> parent,
|
||||
BTPosition<E> left, BTPosition<E> 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<E> getLeft() { return left; }
|
||||
/** Sets the left child of this position */
|
||||
public void setLeft(BTPosition<E> v) { left=v; }
|
||||
/** Returns the right child of this position */
|
||||
public BTPosition<E> getRight() { return right; }
|
||||
/** Sets the right child of this position */
|
||||
public void setRight(BTPosition<E> v) { right=v; }
|
||||
/** Returns the parent of this position */
|
||||
public BTPosition<E> getParent() { return parent; }
|
||||
/** Sets the parent of this position */
|
||||
public void setParent(BTPosition<E> v) { parent=v; }
|
||||
}
|
||||
//end#fragment BTNode
|
||||
20
net/datastructures/BTPosition.java
Normal file
20
net/datastructures/BTPosition.java
Normal file
@@ -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<E> extends Position<E> { // inherits element()
|
||||
public void setElement(E o);
|
||||
public BTPosition<E> getLeft();
|
||||
public void setLeft(BTPosition<E> v);
|
||||
public BTPosition<E> getRight();
|
||||
public void setRight(BTPosition<E> v);
|
||||
public BTPosition<E> getParent();
|
||||
public void setParent(BTPosition<E> v);
|
||||
}
|
||||
//end#fragment BTPos
|
||||
268
net/datastructures/BinarySearchTree.java
Normal file
268
net/datastructures/BinarySearchTree.java
Normal file
@@ -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<K,V>
|
||||
extends LinkedBinaryTree<Entry<K,V>> implements Dictionary<K,V> {
|
||||
//end#fragment BinarySearchTree
|
||||
// Instance variables:
|
||||
//begin#fragment BinarySearchTree
|
||||
protected Comparator<K> C; // comparator
|
||||
protected Position<Entry<K,V>>
|
||||
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<K>();
|
||||
addRoot(null);
|
||||
}
|
||||
//end#fragment BinarySearchTree
|
||||
/** Creates a BinarySearchTree with the given comparator. */
|
||||
//begin#fragment BinarySearchTree
|
||||
public BinarySearchTree(Comparator<K> c) {
|
||||
C = c;
|
||||
addRoot(null);
|
||||
}
|
||||
/** Nested class for location-aware binary search tree entries */
|
||||
protected static class BSTEntry<K,V> implements Entry<K,V> {
|
||||
protected K key;
|
||||
protected V value;
|
||||
protected Position<Entry<K,V>> pos;
|
||||
BSTEntry() { /* default constructor */ }
|
||||
BSTEntry(K k, V v, Position<Entry<K,V>> p) {
|
||||
key = k; value = v; pos = p;
|
||||
}
|
||||
public K getKey() { return key; }
|
||||
public V getValue() { return value; }
|
||||
public Position<Entry<K,V>> 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<Entry<K,V>> position) {
|
||||
return position.element().getKey();
|
||||
}
|
||||
/** Extracts the value of the entry at a given node of the tree. */
|
||||
protected V value(Position<Entry<K,V>> position) {
|
||||
return position.element().getValue();
|
||||
}
|
||||
/** Extracts the entry at a given node of the tree. */
|
||||
protected Entry<K,V> entry(Position<Entry<K,V>> position) {
|
||||
return position.element();
|
||||
}
|
||||
/** Replaces an entry with a new entry (and reset the entry's location) */
|
||||
protected void replaceEntry(Position <Entry<K,V>> pos, Entry<K,V> ent) {
|
||||
((BSTEntry<K,V>) 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<K,V> 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<K,V> insertAtExternal(Position<Entry<K,V>> v, Entry<K,V> 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<Entry<K,V>> v) {
|
||||
removeAboveExternal(v);
|
||||
numEntries--;
|
||||
}
|
||||
/** Auxiliary method used by find, insert, and remove. */
|
||||
protected Position<Entry<K,V>> treeSearch(K key, Position<Entry<K,V>> 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<Entry<K,V>> L,
|
||||
Position<Entry<K,V>> v, K k) {
|
||||
if (isExternal(v)) return;
|
||||
Position<Entry<K,V>> 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<K,V> find(K key) throws InvalidKeyException {
|
||||
checkKey(key); // may throw an InvalidKeyException
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> findAll(K key) throws InvalidKeyException {
|
||||
checkKey(key); // may throw an InvalidKeyException
|
||||
PositionList<Entry<K,V>> L = new NodePositionList<Entry<K,V>>();
|
||||
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<K,V> insert(K k, V x) throws InvalidKeyException {
|
||||
checkKey(k); // may throw an InvalidKeyException
|
||||
Position<Entry<K,V>> 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,V>(k, x, insPos));
|
||||
}
|
||||
//end#fragment BinarySearchTree3
|
||||
/** Removes and returns a given entry. */
|
||||
//begin#fragment BinarySearchTree3
|
||||
public Entry<K,V> remove(Entry<K,V> ent) throws InvalidEntryException {
|
||||
checkEntry(ent); // may throw an InvalidEntryException
|
||||
Position<Entry<K,V>> remPos = ((BSTEntry<K,V>) ent).position();
|
||||
Entry<K,V> 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<Entry<K,V>> swapPos = remPos; // find node for moving entry
|
||||
remPos = right(swapPos);
|
||||
do
|
||||
remPos = left(remPos);
|
||||
while (isInternal(remPos));
|
||||
replaceEntry(swapPos, (Entry<K,V>) 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<Entry<K,V>> entries() {
|
||||
PositionList<Entry<K,V>> entries = new NodePositionList<Entry<K,V>>();
|
||||
Iterable<Position<Entry<K,V>>> positer = positions();
|
||||
for (Position<Entry<K,V>> 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:
|
||||
*
|
||||
* <pre>
|
||||
* 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
|
||||
* </pre>
|
||||
* @return the new root of the restructured subtree
|
||||
*/
|
||||
protected Position<Entry<K,V>> restructure(Position<Entry<K,V>> x) {
|
||||
BTPosition<Entry<K,V>> a, b, c, t1, t2, t3, t4;
|
||||
Position<Entry<K,V>> y = parent(x); // assumes x has a parent
|
||||
Position<Entry<K,V>> z = parent(y); // assumes y has a parent
|
||||
boolean xLeft = (x == left(y));
|
||||
boolean yLeft = (y == left(z));
|
||||
BTPosition<Entry<K,V>> xx = (BTPosition<Entry<K,V>>)x,
|
||||
yy = (BTPosition<Entry<K,V>>)y, zz = (BTPosition<Entry<K,V>>)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<Entry<K,V>> zParent = (BTPosition<Entry<K,V>>)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<K,V>) a.element()).pos = a;
|
||||
((BSTEntry<K,V>) b.element()).pos = b;
|
||||
((BSTEntry<K,V>) c.element()).pos = c;
|
||||
return b; // the new root of this subtree
|
||||
}
|
||||
//begin#fragment BinarySearchTree3
|
||||
} // entries() method is omitted here
|
||||
//end#fragment BinarySearchTree3
|
||||
276
net/datastructures/BinarySearchTreeMap.java
Normal file
276
net/datastructures/BinarySearchTreeMap.java
Normal file
@@ -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<K,V>
|
||||
extends LinkedBinaryTree<Entry<K,V>> implements Map<K,V> {
|
||||
//end#fragment BinarySearchTree
|
||||
// Instance variables:
|
||||
//begin#fragment BinarySearchTree
|
||||
protected Comparator<K> C; // comparator
|
||||
protected Position<Entry<K,V>>
|
||||
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<K>();
|
||||
addRoot(null);
|
||||
}
|
||||
//end#fragment BinarySearchTree
|
||||
/** Creates a BinarySearchTreeMap with the given comparator. */
|
||||
//begin#fragment BinarySearchTree
|
||||
public BinarySearchTreeMap(Comparator<K> c) {
|
||||
C = c;
|
||||
addRoot(null);
|
||||
}
|
||||
/** Nested class for location-aware binary search tree entries */
|
||||
protected static class BSTEntry<K,V> implements Entry<K,V> {
|
||||
protected K key;
|
||||
protected V value;
|
||||
protected Position<Entry<K,V>> pos;
|
||||
BSTEntry() { /* default constructor */ }
|
||||
BSTEntry(K k, V v, Position<Entry<K,V>> p) {
|
||||
key = k; value = v; pos = p;
|
||||
}
|
||||
public K getKey() { return key; }
|
||||
public V getValue() { return value; }
|
||||
public Position<Entry<K,V>> 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<Entry<K,V>> position) {
|
||||
return position.element().getKey();
|
||||
}
|
||||
/** Extracts the value of the entry at a given node of the tree. */
|
||||
protected V value(Position<Entry<K,V>> position) {
|
||||
return position.element().getValue();
|
||||
}
|
||||
/** Extracts the entry at a given node of the tree. */
|
||||
protected Entry<K,V> entry(Position<Entry<K,V>> 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 <Entry<K,V>> pos, Entry<K,V> ent) {
|
||||
((BSTEntry<K,V>) 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<K,V> 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<K,V> insertAtExternal(Position<Entry<K,V>> v, Entry<K,V> 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<Entry<K,V>> v) {
|
||||
removeAboveExternal(v);
|
||||
numEntries--;
|
||||
}
|
||||
/** Auxiliary method used by get, put, and remove. */
|
||||
protected Position<Entry<K,V>> treeSearch(K key, Position<Entry<K,V>> 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<Entry<K,V>> 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<Entry<K,V>> insPos = treeSearch(k, root());
|
||||
BSTEntry<K,V> e = new BSTEntry<K,V>(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<Entry<K,V>> remPos = treeSearch(k, root());
|
||||
if (isExternal(remPos)) return null; // key not found
|
||||
Entry<K,V> 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<Entry<K,V>> swapPos = remPos; // find node for moving entry
|
||||
remPos = right(swapPos);
|
||||
do
|
||||
remPos = left(remPos);
|
||||
while (isInternal(remPos));
|
||||
replaceEntry(swapPos, (Entry<K,V>) 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<K> keySet() {
|
||||
PositionList<K> keys = new NodePositionList<K>();
|
||||
Iterable<Position<Entry<K,V>>> positer = positions();
|
||||
for (Position<Entry<K,V>> cur: positer)
|
||||
if (isInternal(cur))
|
||||
keys.addLast(key(cur));
|
||||
return keys;
|
||||
}
|
||||
/** Returns an iterable object containing all values in the tree. */
|
||||
public Iterable<V> values() {
|
||||
PositionList<V> vals = new NodePositionList<V>();
|
||||
Iterable<Position<Entry<K,V>>> positer = positions();
|
||||
for (Position<Entry<K,V>> cur: positer)
|
||||
if (isInternal(cur))
|
||||
vals.addLast(value(cur));
|
||||
return vals;
|
||||
}
|
||||
/** Returns an iterable object containing all entries in the tree. */
|
||||
public Iterable<Entry<K,V>> entrySet() {
|
||||
PositionList<Entry<K,V>> entries = new NodePositionList<Entry<K,V>>();
|
||||
Iterable<Position<Entry<K,V>>> positer = positions();
|
||||
for (Position<Entry<K,V>> 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:
|
||||
*
|
||||
* <pre>
|
||||
* 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
|
||||
* </pre>
|
||||
* @return the new root of the restructured subtree
|
||||
*/
|
||||
protected Position<Entry<K,V>> restructure(Position<Entry<K,V>> x) {
|
||||
BTPosition<Entry<K,V>> a, b, c, t1, t2, t3, t4;
|
||||
Position<Entry<K,V>> y = parent(x); // assumes x has a parent
|
||||
Position<Entry<K,V>> z = parent(y); // assumes y has a parent
|
||||
boolean xLeft = (x == left(y));
|
||||
boolean yLeft = (y == left(z));
|
||||
BTPosition<Entry<K,V>> xx = (BTPosition<Entry<K,V>>)x,
|
||||
yy = (BTPosition<Entry<K,V>>)y, zz = (BTPosition<Entry<K,V>>)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<Entry<K,V>> zParent = (BTPosition<Entry<K,V>>)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<K,V>) a.element()).pos = a;
|
||||
((BSTEntry<K,V>) b.element()).pos = b;
|
||||
((BSTEntry<K,V>) c.element()).pos = c;
|
||||
return b; // the new root of this subtree
|
||||
}
|
||||
//begin#fragment BinarySearchTree3
|
||||
}
|
||||
//end#fragment BinarySearchTree3
|
||||
22
net/datastructures/BinaryTree.java
Normal file
22
net/datastructures/BinaryTree.java
Normal file
@@ -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<E> extends Tree<E> {
|
||||
/** Returns the left child of a node. */
|
||||
public Position<E> left(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException;
|
||||
/** Returns the right child of a node. */
|
||||
public Position<E> right(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException;
|
||||
/** Returns whether a node has a left child. */
|
||||
public boolean hasLeft(Position<E> v) throws InvalidPositionException;
|
||||
/** Returns whether a node has a right child. */
|
||||
public boolean hasRight(Position<E> v) throws InvalidPositionException;
|
||||
}
|
||||
//end#fragment Tree
|
||||
13
net/datastructures/BoundaryViolationException.java
Normal file
13
net/datastructures/BoundaryViolationException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
25
net/datastructures/CompleteBinaryTree.java
Normal file
25
net/datastructures/CompleteBinaryTree.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.datastructures;
|
||||
/**
|
||||
* An interface for a complete binary tree. A binary tree with height
|
||||
* <tt>h</tt> is <b>complete</b> if the levels 0,1,2,...,<tt>h</tt> -
|
||||
* 1 have the maximum number of nodes possible (that is, level
|
||||
* <tt>i</tt> has 2<sup>i</sup> nodes, for 0 <= <tt>i</tt> <=
|
||||
* <tt>h</tt> - 1) and in level <tt>h</tt> - 1 all the internal nodes
|
||||
* are to the left of the external nodes.
|
||||
*
|
||||
* @author Michael Goodrich
|
||||
*/
|
||||
//begin#fragment HeapTree
|
||||
public interface CompleteBinaryTree<E> extends BinaryTree<E> {
|
||||
//end#fragment HeapTree
|
||||
/** Adds an element to the tree just after the last node. Returns
|
||||
* the newly created position. */
|
||||
//begin#fragment HeapTree
|
||||
public Position<E> 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
|
||||
20
net/datastructures/ComponentsDFS.java
Normal file
20
net/datastructures/ComponentsDFS.java
Normal file
@@ -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<V, E> extends DFS<V, E, Object, Integer> {
|
||||
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) { v.put(COMPONENT, compNumber);}
|
||||
protected Integer finalResult(Integer dfsResult) {
|
||||
for (Vertex<V> 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
|
||||
24
net/datastructures/ConnectivityDFS.java
Normal file
24
net/datastructures/ConnectivityDFS.java
Normal file
@@ -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<V, E> extends DFS <V, E, Object, Boolean> {
|
||||
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 <tt>true</tt> if the graph is
|
||||
* connected, <tt>false</tt> otherwise
|
||||
*/
|
||||
//begin#fragment ConnectivityTesterDFS
|
||||
protected void setup() { reached = 0; }
|
||||
protected void startVisit(Vertex<V> v) { reached++; }
|
||||
protected Boolean finalResult(Boolean dfsResult) {
|
||||
return new Boolean(reached == graph.numVertices());
|
||||
}
|
||||
}
|
||||
//end#fragment ConnectivityTesterDFS
|
||||
101
net/datastructures/DFS.java
Normal file
101
net/datastructures/DFS.java
Normal file
@@ -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<V, E, I, R> {
|
||||
protected Graph<V, E> graph; // The graph being traversed
|
||||
protected Vertex<V> 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<V, E> g, Vertex<V> s, I in) {
|
||||
graph = g;
|
||||
start = s;
|
||||
info = in;
|
||||
for(Vertex<V> v: graph.vertices()) unVisit(v); // mark vertices as unvisited
|
||||
for(Edge<E> 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> v) {
|
||||
initResult();
|
||||
if (!isDone())
|
||||
startVisit(v);
|
||||
if (!isDone()) {
|
||||
visit(v);
|
||||
for (Edge<E> e: graph.incidentEdges(v)) {
|
||||
if (!isVisited(e)) {
|
||||
// found an unexplored edge, explore it
|
||||
visit(e);
|
||||
Vertex<V> 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> v) {}
|
||||
/** Called after we finish the visit for a vertex (v). */
|
||||
protected void finishVisit(Vertex<V> v) {}
|
||||
/** Called when we traverse a discovery edge (e) from a vertex (from). */
|
||||
protected void traverseDiscovery(Edge<E> e, Vertex<V> from) {}
|
||||
/** Called when we traverse a back edge (e) from a vertex (from). */
|
||||
protected void traverseBack(Edge<E> e, Vertex<V> 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
|
||||
32
net/datastructures/DLNode.java
Normal file
32
net/datastructures/DLNode.java
Normal file
@@ -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 <code>DNode</code> class in that it
|
||||
* does not implement the <code>Position</code> interface, for
|
||||
* simplification purposes.
|
||||
*
|
||||
* @author Roberto Tamassia
|
||||
* @see DNode
|
||||
* @see Position
|
||||
*/
|
||||
|
||||
//begin#fragment DLNode
|
||||
public class DLNode<E> {
|
||||
private E element;
|
||||
private DLNode<E> next, prev;
|
||||
DLNode() { this(null, null, null); }
|
||||
DLNode(E e, DLNode<E> p, DLNode<E> n) {
|
||||
element = e;
|
||||
next = n;
|
||||
prev = p;
|
||||
}
|
||||
public void setElement(E newElem) { element = newElem; }
|
||||
public void setNext(DLNode<E> newNext) { next = newNext; }
|
||||
public void setPrev(DLNode<E> newPrev) { prev = newPrev; }
|
||||
public E getElement() { return element; }
|
||||
public DLNode<E> getNext() { return next; }
|
||||
public DLNode<E> getPrev() { return prev; }
|
||||
}
|
||||
//end#fragment DLNode
|
||||
32
net/datastructures/DNode.java
Normal file
32
net/datastructures/DNode.java
Normal file
@@ -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<E> implements Position<E> {
|
||||
private DNode<E> prev, next; // References to the nodes before and after
|
||||
private E element; // Element stored in this position
|
||||
/** Constructor */
|
||||
public DNode(DNode<E> newPrev, DNode<E> 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<E> getNext() { return next; }
|
||||
public DNode<E> getPrev() { return prev; }
|
||||
// Update methods
|
||||
public void setNext(DNode<E> newNext) { next = newNext; }
|
||||
public void setPrev(DNode<E> newPrev) { prev = newPrev; }
|
||||
public void setElement(E newElement) { element = newElement; }
|
||||
}
|
||||
//end#fragment DNode
|
||||
13
net/datastructures/DecorablePosition.java
Normal file
13
net/datastructures/DecorablePosition.java
Normal file
@@ -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<E>
|
||||
extends Position<E>, Map<Object,Object> {
|
||||
} // no new methods needed -- this is a mixture of Position and Map.
|
||||
//end#fragment Decorable
|
||||
22
net/datastructures/DefaultComparator.java
Normal file
22
net/datastructures/DefaultComparator.java
Normal file
@@ -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<E> implements Comparator<E> {
|
||||
//end#fragment DefaultComparator
|
||||
/** Compares two given elements
|
||||
*
|
||||
* @return a negative integer if <tt>a</tt> is less than <tt>b</tt>,
|
||||
* zero if <tt>a</tt> equals <tt>b</tt>, or a positive integer if
|
||||
* <tt>a</tt> is greater than <tt>b</tt>
|
||||
*/
|
||||
//begin#fragment DefaultComparator
|
||||
public int compare(E a, E b) throws ClassCastException {
|
||||
return ((Comparable<E>) a).compareTo(b);
|
||||
}
|
||||
}
|
||||
//end#fragment DefaultComparator
|
||||
45
net/datastructures/Deque.java
Normal file
45
net/datastructures/Deque.java
Normal file
@@ -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<E> {
|
||||
/**
|
||||
* 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
|
||||
46
net/datastructures/Dictionary.java
Normal file
46
net/datastructures/Dictionary.java
Normal file
@@ -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<K,V> {
|
||||
//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 <tt>null</tt> if
|
||||
* no such entry exists. */
|
||||
//begin#fragment Dictionary
|
||||
public Entry<K,V> 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<Entry<K,V>> findAll(K key)
|
||||
throws InvalidKeyException;
|
||||
//end#fragment Dictionary
|
||||
/** Inserts an item into the dictionary. Returns the newly created
|
||||
* entry. */
|
||||
//begin#fragment Dictionary
|
||||
public Entry<K,V> insert(K key, V value)
|
||||
throws InvalidKeyException;
|
||||
//end#fragment Dictionary
|
||||
/** Removes and returns the given entry from the dictionary. */
|
||||
//begin#fragment Dictionary
|
||||
public Entry<K,V> remove(Entry<K,V> e)
|
||||
throws InvalidEntryException;
|
||||
//end#fragment Dictionary
|
||||
/** Returns an iterator containing all the entries in the dictionary. */
|
||||
//begin#fragment Dictionary
|
||||
public Iterable<Entry<K,V>> entries();
|
||||
}
|
||||
//end#fragment Dictionary
|
||||
97
net/datastructures/Dijkstra.java
Normal file
97
net/datastructures/Dijkstra.java
Normal file
@@ -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.
|
||||
*
|
||||
* <p>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<V, E> {
|
||||
/** Infinity value. */
|
||||
protected static final Integer INFINITE = Integer.MAX_VALUE;
|
||||
/** Input graph. */
|
||||
protected Graph<V, E> 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<Integer, Vertex<V>> Q;
|
||||
/** Executes Dijkstra's algorithm.
|
||||
* @param g Input graph
|
||||
* @param s Source vertex
|
||||
* @param w Weight decoration object */
|
||||
public void execute(Graph<V, E> g, Vertex<V> s, Object w) {
|
||||
graph = g;
|
||||
WEIGHT = w;
|
||||
DefaultComparator dc = new DefaultComparator();
|
||||
Q = new HeapAdaptablePriorityQueue<Integer, Vertex<V>>(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 <tt>u</tt> 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<V> 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> v) {
|
||||
// store all the vertices in priority queue Q
|
||||
for (Vertex<V> u: graph.vertices()) {
|
||||
int u_dist;
|
||||
if (u==v)
|
||||
u_dist = 0;
|
||||
else
|
||||
u_dist = INFINITE;
|
||||
Entry<Integer, Vertex<V>> 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<Integer, Vertex<V>> u_entry = Q.min();
|
||||
Vertex<V> 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> e: graph.incidentEdges(u)) {
|
||||
Vertex<V> z = graph.opposite(u,e);
|
||||
Entry<Integer, Vertex<V>> z_entry
|
||||
= (Entry<Integer, Vertex<V>>) 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
|
||||
6
net/datastructures/Edge.java
Normal file
6
net/datastructures/Edge.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package net.datastructures;
|
||||
/**
|
||||
* An interface for an edge of a graph.
|
||||
* @author Roberto Tamassia
|
||||
*/
|
||||
public interface Edge<E> extends DecorablePosition<E> { }
|
||||
45
net/datastructures/ElementIterator.java
Normal file
45
net/datastructures/ElementIterator.java
Normal file
@@ -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<E> implements Iterator<E> {
|
||||
protected PositionList<E> list; // the underlying list
|
||||
protected Position<E> cursor; // the next position
|
||||
/** Creates an element iterator over the given list. */
|
||||
public ElementIterator(PositionList<E> 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
|
||||
16
net/datastructures/EmptyDequeException.java
Normal file
16
net/datastructures/EmptyDequeException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
11
net/datastructures/EmptyListException.java
Normal file
11
net/datastructures/EmptyListException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
11
net/datastructures/EmptyPriorityQueueException.java
Normal file
11
net/datastructures/EmptyPriorityQueueException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
15
net/datastructures/EmptyQueueException.java
Normal file
15
net/datastructures/EmptyQueueException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
16
net/datastructures/EmptyStackException.java
Normal file
16
net/datastructures/EmptyStackException.java
Normal file
@@ -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
|
||||
11
net/datastructures/EmptyTreeException.java
Normal file
11
net/datastructures/EmptyTreeException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
11
net/datastructures/Entry.java
Normal file
11
net/datastructures/Entry.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.datastructures;
|
||||
|
||||
//begin#fragment Entry
|
||||
/** Interface for a key-value pair entry **/
|
||||
public interface Entry<K,V> {
|
||||
/** Returns the key stored in this entry. */
|
||||
public K getKey();
|
||||
/** Returns the value stored in this entry. */
|
||||
public V getValue();
|
||||
}
|
||||
//end#fragment Entry
|
||||
49
net/datastructures/EulerTour.java
Normal file
49
net/datastructures/EulerTour.java
Normal file
@@ -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<E, R> {
|
||||
protected BinaryTree<E> tree;
|
||||
/** Execution of the traversal. This abstract method must be
|
||||
* specified in a concrete subclass. */
|
||||
public abstract R execute(BinaryTree<E> T);
|
||||
/** Initialization of the traversal */
|
||||
protected void init(BinaryTree<E> T) { tree = T; }
|
||||
/** Template method */
|
||||
protected R eulerTour(Position<E> v) {
|
||||
TourResult<R> r = new TourResult<R>();
|
||||
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<E> v, TourResult<R> r) {}
|
||||
/** Method called for the visit on from below */
|
||||
protected void visitBelow(Position<E> v, TourResult<R> r) {}
|
||||
/** Method called for the visit on the right */
|
||||
protected void visitRight(Position<E> v, TourResult<R> r) {}
|
||||
|
||||
//end#fragment EulerTour
|
||||
|
||||
//begin#fragment TourResult
|
||||
public class TourResult<R> {
|
||||
public R left;
|
||||
public R right;
|
||||
public R out;
|
||||
}
|
||||
//end#fragment TourResult
|
||||
//begin#fragment EulerTour
|
||||
}
|
||||
//end#fragment EulerTour
|
||||
54
net/datastructures/FindCycleDFS.java
Normal file
54
net/datastructures/FindCycleDFS.java
Normal file
@@ -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<V, E>
|
||||
extends DFS<V, E, Object, Iterable<Position>> {
|
||||
protected PositionList<Position> cycle; // sequence of edges of the cycle
|
||||
protected boolean done;
|
||||
protected Vertex<V> 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<Position>();
|
||||
done = false;
|
||||
}
|
||||
protected void startVisit(Vertex<V> v) { cycle.addLast(v); }
|
||||
protected void finishVisit(Vertex<V> 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> e, Vertex<V> from) {
|
||||
cycle.addLast(e);
|
||||
}
|
||||
protected void traverseBack(Edge<E> e, Vertex<V> 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<Position> finalResult(Iterable<Position> r) {
|
||||
// remove the vertices and edges from start to cycleStart
|
||||
if (!cycle.isEmpty()) {
|
||||
for (Position<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
|
||||
|
||||
38
net/datastructures/FindPathDFS.java
Normal file
38
net/datastructures/FindPathDFS.java
Normal file
@@ -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<V, E>
|
||||
extends DFS<V, E, Vertex<V>, Iterable<Position>> {
|
||||
protected PositionList<Position> path;
|
||||
protected boolean done;
|
||||
/** Setup method to initialize the path. */
|
||||
public void setup() {
|
||||
path = new NodePositionList<Position>();
|
||||
done = false;
|
||||
}
|
||||
protected void startVisit(Vertex<V> v) {
|
||||
path.addLast(v); // add vertex v to path
|
||||
if (v == info)
|
||||
done = true;
|
||||
}
|
||||
protected void finishVisit(Vertex<V> 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> e, Vertex<V> from) {
|
||||
path.addLast(e); // add edge e to the path
|
||||
}
|
||||
protected boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
public Iterable<Position> finalResult(Iterable<Position> r) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
//end#fragment FindPathDFS
|
||||
13
net/datastructures/FullStackException.java
Normal file
13
net/datastructures/FullStackException.java
Normal file
@@ -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
|
||||
47
net/datastructures/Graph.java
Normal file
47
net/datastructures/Graph.java
Normal file
@@ -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<V, E> {
|
||||
/** 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<Vertex<V>> vertices();
|
||||
/** Returns the edges of the graph as an iterable collection */
|
||||
public Iterable<Edge<E>> edges();
|
||||
/** Replaces the element of a given vertex with a new element and
|
||||
returns the old element */
|
||||
public V replace(Vertex<V> 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<E> p, E o) throws InvalidPositionException;
|
||||
/** Returns the edges incident on a vertex as an iterable collection */
|
||||
public Iterable<Edge<E>> incidentEdges(Vertex<V> v)
|
||||
throws InvalidPositionException;
|
||||
/** Returns the endvertices of a vertex as an array of length 2 */
|
||||
public Vertex[] endVertices(Edge<E> e) throws InvalidPositionException;
|
||||
/** Returns the other endvertex of an incident edge */
|
||||
public Vertex<V> opposite(Vertex<V> v, Edge<E> e)
|
||||
throws InvalidPositionException;
|
||||
/** Tests whether two vertices are adjacent */
|
||||
public boolean areAdjacent(Vertex<V> u, Vertex<V> v)
|
||||
throws InvalidPositionException;
|
||||
/** Inserts and return a new vertex with a given element */
|
||||
public Vertex<V> insertVertex(V o);
|
||||
/** Inserts and return a new edge with a given element between two
|
||||
vertices */
|
||||
public Edge<E> insertEdge(Vertex<V> u, Vertex<V> 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> v) throws InvalidPositionException;
|
||||
/** Removes an edge and return its element */
|
||||
public E removeEdge(Edge<E> e) throws InvalidPositionException;
|
||||
}
|
||||
//end#fragment Graph
|
||||
|
||||
177
net/datastructures/HashTableMap.java
Normal file
177
net/datastructures/HashTableMap.java
Normal file
@@ -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<K,V> implements Map<K,V> {
|
||||
//end#fragment Header
|
||||
/** Nested class for an entry in a hash table. */
|
||||
//begin#fragment Header
|
||||
public static class HashEntry<K,V> implements Entry<K,V> {
|
||||
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<K,V> ent;
|
||||
try { ent = (HashEntry<K,V>) 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<K,V> AVAILABLE = new HashEntry<K,V>(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<K,V>[] 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<K,V>[]) 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<K> keySet() {
|
||||
PositionList<K> keys = new NodePositionList<K>();
|
||||
for (int i=0; i<capacity; i++)
|
||||
if ((bucket[i] != null) && (bucket[i] != AVAILABLE))
|
||||
keys.addLast(bucket[i].getKey());
|
||||
return keys;
|
||||
}
|
||||
/** Helper search method - returns index of found key or -(a + 1),
|
||||
* where a is the index of the first empty or available slot found. */
|
||||
protected int findEntry(K key) throws InvalidKeyException {
|
||||
int avail = -1;
|
||||
checkKey(key);
|
||||
int i = hashValue(key);
|
||||
int j = i;
|
||||
do {
|
||||
Entry<K,V> 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<K,V>) 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<K,V>(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<K,V>[] old = bucket;
|
||||
bucket = (Entry<K,V>[]) 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<old.length; i++) {
|
||||
Entry<K,V> 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<Entry<K,V>> entrySet() {
|
||||
PositionList<Entry<K,V>> entries = new NodePositionList<Entry<K,V>>();
|
||||
for (int i=0; i<capacity; i++)
|
||||
if ((bucket[i] != null) && (bucket[i] != AVAILABLE))
|
||||
entries.addLast(bucket[i]);
|
||||
return entries;
|
||||
}
|
||||
/** Returns an iterable object containing all of the values. */
|
||||
public Iterable<V> values() {
|
||||
PositionList<V> values = new NodePositionList<V>();
|
||||
for (int i=0; i<capacity; i++)
|
||||
if ((bucket[i] != null) && (bucket[i] != AVAILABLE))
|
||||
values.addLast(bucket[i].getValue());
|
||||
return values;
|
||||
}
|
||||
//begin#fragment Linear2
|
||||
}
|
||||
//end#fragment Linear2
|
||||
128
net/datastructures/HeapPriorityQueue.java
Normal file
128
net/datastructures/HeapPriorityQueue.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package net.datastructures;
|
||||
import java.util.Comparator;
|
||||
|
||||
//begin#fragment HeapPriorityQueue
|
||||
/**
|
||||
* Realization of a priority queue by means of a heap. A complete
|
||||
* binary tree realized by means of an array list is used to
|
||||
* represent the heap.
|
||||
//end#fragment HeapPriorityQueue
|
||||
*
|
||||
* @author Roberto Tamassia, Michael Goodrich, Eric Zamore
|
||||
//begin#fragment HeapPriorityQueue
|
||||
*/
|
||||
public class HeapPriorityQueue<K,V> implements PriorityQueue<K,V> {
|
||||
protected CompleteBinaryTree<Entry<K,V>> heap; // underlying heap
|
||||
protected Comparator<K> comp; // comparator for the keys
|
||||
/** Inner class for heap entries. */
|
||||
protected static class MyEntry<K,V> implements Entry<K,V> {
|
||||
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<Entry<K,V>>(); // use an array list
|
||||
comp = new DefaultComparator<K>(); // use the default comparator
|
||||
}
|
||||
/** Creates an empty heap with the given comparator */
|
||||
public HeapPriorityQueue(Comparator<K> c) {
|
||||
heap = new ArrayListCompleteBinaryTree<Entry<K,V>>();
|
||||
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<K> 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<K,V> 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<K,V> insert(K k, V x) throws InvalidKeyException {
|
||||
checkKey(k); // may throw an InvalidKeyException
|
||||
Entry<K,V> entry = new MyEntry<K,V>(k,x);
|
||||
upHeap(heap.add(entry));
|
||||
return entry;
|
||||
}
|
||||
/** Removes and returns an entry with minimum key */
|
||||
public Entry<K,V> removeMin() throws EmptyPriorityQueueException {
|
||||
if (isEmpty())
|
||||
throw new EmptyPriorityQueueException("Priority queue is empty");
|
||||
Entry<K,V> 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<Entry<K,V>> v) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> r) {
|
||||
while (heap.isInternal(r)) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> x, Position<Entry<K,V>> y) {
|
||||
Entry<K,V> 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
|
||||
}
|
||||
33
net/datastructures/IndexList.java
Normal file
33
net/datastructures/IndexList.java
Normal file
@@ -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<E> {
|
||||
//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
|
||||
10
net/datastructures/InvalidEntryException.java
Normal file
10
net/datastructures/InvalidEntryException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
11
net/datastructures/InvalidKeyException.java
Normal file
11
net/datastructures/InvalidKeyException.java
Normal file
@@ -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;
|
||||
}
|
||||
18
net/datastructures/InvalidPositionException.java
Normal file
18
net/datastructures/InvalidPositionException.java
Normal file
@@ -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
|
||||
314
net/datastructures/LinkedBinaryTree.java
Normal file
314
net/datastructures/LinkedBinaryTree.java
Normal file
@@ -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<E> implements BinaryTree<E> {
|
||||
protected BTPosition<E> 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<E> 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<E> v) throws InvalidPositionException {
|
||||
return !isInternal(v);
|
||||
}
|
||||
//begin#fragment LinkedBinaryTree
|
||||
/** Returns whether a node is the root. */
|
||||
public boolean isRoot(Position<E> v) throws InvalidPositionException {
|
||||
checkPosition(v);
|
||||
return (v == root());
|
||||
}
|
||||
/** Returns whether a node has a left child. */
|
||||
public boolean hasLeft(Position<E> v) throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
return (vv.getLeft() != null);
|
||||
}
|
||||
//end#fragment LinkedBinaryTree
|
||||
/** Returns whether a node has a right child. */
|
||||
public boolean hasRight(Position<E> v) throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
return (vv.getRight() != null);
|
||||
}
|
||||
//begin#fragment LinkedBinaryTree
|
||||
/** Returns the root of the tree. */
|
||||
public Position<E> root() throws EmptyTreeException {
|
||||
if (root == null)
|
||||
throw new EmptyTreeException("The tree is empty");
|
||||
return root;
|
||||
}
|
||||
/** Returns the left child of a node. */
|
||||
public Position<E> left(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
Position<E> 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<E> right(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
Position<E> 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<E> parent(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
Position<E> 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<Position<E>> children(Position<E> v)
|
||||
throws InvalidPositionException {
|
||||
PositionList<Position<E>> children = new NodePositionList<Position<E>>();
|
||||
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<Position<E>> positions() {
|
||||
PositionList<Position<E>> positions = new NodePositionList<Position<E>>();
|
||||
if(size != 0)
|
||||
preorderPositions(root(), positions); // assign positions in preorder
|
||||
return positions;
|
||||
}
|
||||
/** Returns an iterator of the elements stored at the nodes */
|
||||
public Iterator<E> iterator() {
|
||||
Iterable<Position<E>> positions = positions();
|
||||
PositionList<E> elements = new NodePositionList<E>();
|
||||
for (Position<E> pos: positions)
|
||||
elements.addLast(pos.element());
|
||||
return elements.iterator(); // An iterator of elements
|
||||
}
|
||||
/** Replaces the element at a node. */
|
||||
public E replace(Position<E> v, E o)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> 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<E> sibling(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
BTPosition<E> parentPos = vv.getParent();
|
||||
if (parentPos != null) {
|
||||
BTPosition<E> sibPos;
|
||||
BTPosition<E> 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<E> 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<E> insertLeft(Position<E> v, E e)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
Position<E> leftPos = vv.getLeft();
|
||||
if (leftPos != null)
|
||||
throw new InvalidPositionException("Node already has a left child");
|
||||
BTPosition<E> 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<E> insertRight(Position<E> v, E e)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
Position<E> rightPos = vv.getRight();
|
||||
if (rightPos != null)
|
||||
throw new InvalidPositionException("Node already has a right child");
|
||||
BTPosition<E> 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<E> v)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
BTPosition<E> leftPos = vv.getLeft();
|
||||
BTPosition<E> rightPos = vv.getRight();
|
||||
if (leftPos != null && rightPos != null)
|
||||
throw new InvalidPositionException("Cannot remove node with two children");
|
||||
BTPosition<E> 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<E> 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<E> v, BinaryTree<E> T1, BinaryTree<E> T2)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> 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<E> r1 = checkPosition(T1.root());
|
||||
vv.setLeft(r1);
|
||||
r1.setParent(vv); // T1 should be invalidated
|
||||
}
|
||||
if (!T2.isEmpty()) {
|
||||
BTPosition<E> 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<E> v, Position<E> w)
|
||||
throws InvalidPositionException {
|
||||
BTPosition<E> vv = checkPosition(v);
|
||||
BTPosition<E> 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<E> 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<E> v)
|
||||
throws InvalidPositionException {
|
||||
if (!isExternal(v))
|
||||
throw new InvalidPositionException("Node is not external");
|
||||
if (isRoot(v))
|
||||
remove(v);
|
||||
else {
|
||||
Position<E> 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<E> checkPosition(Position<E> v)
|
||||
throws InvalidPositionException {
|
||||
if (v == null || !(v instanceof BTPosition))
|
||||
throw new InvalidPositionException("The position is invalid");
|
||||
return (BTPosition<E>) v;
|
||||
}
|
||||
/** Creates a new binary tree node */
|
||||
protected BTPosition<E> createNode(E element, BTPosition<E> parent,
|
||||
BTPosition<E> left, BTPosition<E> right) {
|
||||
return new BTNode<E>(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<E> v, PositionList<Position<E>> 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<E> v, PositionList<Position<E>> 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
|
||||
}
|
||||
}
|
||||
138
net/datastructures/LinkedTree.java
Normal file
138
net/datastructures/LinkedTree.java
Normal file
@@ -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<E> implements Tree<E> {
|
||||
protected TreePosition<E> 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<E> v) throws InvalidPositionException {
|
||||
return !isExternal(v);
|
||||
}
|
||||
//end#fragment LinkedTree
|
||||
/** Returns whether a node is external. */
|
||||
public boolean isExternal(Position<E> v) throws InvalidPositionException {
|
||||
TreePosition<E> 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<E> v) throws InvalidPositionException {
|
||||
checkPosition(v);
|
||||
return (v == root());
|
||||
}
|
||||
//begin#fragment LinkedTree
|
||||
/** Returns the root of the tree. */
|
||||
public Position<E> 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<E> parent(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
TreePosition<E> vv = checkPosition(v);
|
||||
Position<E> 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<Position<E>> children(Position<E> v)
|
||||
throws InvalidPositionException {
|
||||
TreePosition<E> 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<Position<E>> positions() {
|
||||
PositionList<Position<E>> positions = new NodePositionList<Position<E>>();
|
||||
if(size != 0)
|
||||
preorderPositions(root(), positions); // assign positions in preorder
|
||||
return positions;
|
||||
}
|
||||
/** Returns an iterator of the elements stored at the nodes */
|
||||
public Iterator<E> iterator() {
|
||||
Iterable<Position<E>> positions = positions();
|
||||
PositionList<E> elements = new NodePositionList<E>();
|
||||
for (Position<E> pos: positions)
|
||||
elements.addLast(pos.element());
|
||||
return elements.iterator(); // An iterator of elements
|
||||
}
|
||||
/** Replaces the element at a node. */
|
||||
public E replace(Position<E> v, E o)
|
||||
throws InvalidPositionException {
|
||||
TreePosition<E> 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<E> 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<E> v, Position<E> w)
|
||||
throws InvalidPositionException {
|
||||
TreePosition<E> vv = checkPosition(v);
|
||||
TreePosition<E> 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<E> checkPosition(Position<E> v)
|
||||
throws InvalidPositionException {
|
||||
if (v == null || !(v instanceof TreePosition))
|
||||
throw new InvalidPositionException("The position is invalid");
|
||||
return (TreePosition<E>) v;
|
||||
}
|
||||
/** Creates a new tree node */
|
||||
protected TreePosition<E> createNode(E element, TreePosition<E> parent,
|
||||
PositionList<Position<E>> children) {
|
||||
return new TreeNode<E>(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<E> v, PositionList<Position<E>> pos)
|
||||
throws InvalidPositionException {
|
||||
pos.addLast(v);
|
||||
for (Position<E> w : children(v))
|
||||
preorderPositions(w, pos); // recurse on each child
|
||||
}
|
||||
}
|
||||
//end#fragment LinkedTree5
|
||||
36
net/datastructures/Map.java
Normal file
36
net/datastructures/Map.java
Normal file
@@ -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<K,V> {
|
||||
/** 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<K> keySet();
|
||||
/** Returns an iterable object containing all the values in the map. */
|
||||
public Iterable<V> values();
|
||||
/** Returns an iterable object containing all the entries in the map. */
|
||||
public Iterable<Entry<K,V>> entrySet();
|
||||
}
|
||||
//end#fragment Map
|
||||
39
net/datastructures/Node.java
Normal file
39
net/datastructures/Node.java
Normal file
@@ -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<E> {
|
||||
// Instance variables:
|
||||
private E element;
|
||||
private Node<E> 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<E> n) {
|
||||
element = e;
|
||||
next = n;
|
||||
}
|
||||
// Accessor methods:
|
||||
public E getElement() {
|
||||
return element;
|
||||
}
|
||||
public Node<E> getNext() {
|
||||
return next;
|
||||
}
|
||||
// Modifier methods:
|
||||
public void setElement(E newElem) {
|
||||
element = newElem;
|
||||
}
|
||||
public void setNext(Node<E> newNext) {
|
||||
next = newNext;
|
||||
}
|
||||
}
|
||||
//end#fragment Node
|
||||
113
net/datastructures/NodeDeque.java
Normal file
113
net/datastructures/NodeDeque.java
Normal file
@@ -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<E> implements Deque<E> {
|
||||
protected DLNode<E> 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<E>();
|
||||
trailer = new DLNode<E>();
|
||||
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<E> second = header.getNext();
|
||||
DLNode<E> first = new DLNode<E>(o, header, second);
|
||||
second.setPrev(first);
|
||||
header.setNext(first);
|
||||
size++;
|
||||
}
|
||||
//end#fragment addFirst
|
||||
|
||||
public void addLast(E o) {
|
||||
DLNode<E> secondtolast = trailer.getPrev();
|
||||
DLNode<E> last = new DLNode<E>(o, secondtolast, trailer);
|
||||
secondtolast.setNext(last);
|
||||
trailer.setPrev(last);
|
||||
size++;
|
||||
}
|
||||
|
||||
public E removeFirst() throws EmptyDequeException {
|
||||
if (isEmpty())
|
||||
throw new EmptyDequeException("Deque is empty.");
|
||||
DLNode<E> first = header.getNext();
|
||||
E o = first.getElement();
|
||||
DLNode<E> 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<E> last = trailer.getPrev();
|
||||
E o = last.getElement();
|
||||
DLNode<E> secondtolast = last.getPrev();
|
||||
trailer.setPrev(secondtolast);
|
||||
secondtolast.setNext(trailer);
|
||||
size--;
|
||||
return o;
|
||||
}
|
||||
//end#fragment removeLast
|
||||
|
||||
//begin#fragment tail
|
||||
}
|
||||
//end#fragment tail
|
||||
232
net/datastructures/NodePositionList.java
Normal file
232
net/datastructures/NodePositionList.java
Normal file
@@ -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<E> implements PositionList<E> {
|
||||
//end#fragment Header
|
||||
//begin#fragment Listvars
|
||||
protected int numElts; // Number of elements in the list
|
||||
protected DNode<E> 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<E>(null, null, null); // create header
|
||||
trailer = new DNode<E>(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<E> checkPosition(Position<E> 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<E> temp = (DNode<E>) 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<E> 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<E> 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<E> prev(Position<E> p)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
DNode<E> 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<E> next(Position<E> p)
|
||||
throws InvalidPositionException, BoundaryViolationException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
DNode<E> 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<E> p, E element)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
numElts++;
|
||||
DNode<E> newNode = new DNode<E>(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<E> p, E element)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
numElts++;
|
||||
DNode<E> newNode = new DNode<E>(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<E> newNode = new DNode<E>(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<E> oldLast = trailer.getPrev();
|
||||
DNode<E> newNode = new DNode<E>(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<E> p)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
numElts--;
|
||||
DNode<E> vPrev = v.getPrev();
|
||||
DNode<E> 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<E> p, E element)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> 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<E> iterator() { return new ElementIterator<E>(this); }
|
||||
//end#fragment Iterator
|
||||
//begin#fragment PIterator
|
||||
/** Returns an iterable collection of all the nodes in the list. */
|
||||
public Iterable<Position<E>> positions() { // create a list of posiitons
|
||||
PositionList<Position<E>> P = new NodePositionList<Position<E>>();
|
||||
if (!isEmpty()) {
|
||||
Position<E> 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<E> p)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
return v.getPrev() == header;
|
||||
}
|
||||
/** Returns whether a position is the last one; O(1) time */
|
||||
public boolean isLast(Position<E> p)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> v = checkPosition(p);
|
||||
return v.getNext() == trailer;
|
||||
}
|
||||
/** Swap the elements of two give positions; O(1) time */
|
||||
public void swapElements(Position<E> a, Position<E> b)
|
||||
throws InvalidPositionException {
|
||||
DNode<E> pA = checkPosition(a);
|
||||
DNode<E> 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 <E> String forEachToString(PositionList<E> 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 <E> String toString(PositionList<E> l) {
|
||||
Iterator<E> 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);
|
||||
}
|
||||
}
|
||||
128
net/datastructures/NodeQueue.java
Normal file
128
net/datastructures/NodeQueue.java
Normal file
@@ -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<E> implements Queue<E> {
|
||||
|
||||
protected Node<E> 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<E> node = new Node<E>();
|
||||
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<Integer> A = new NodeQueue<Integer>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
116
net/datastructures/NodeStack.java
Normal file
116
net/datastructures/NodeStack.java
Normal file
@@ -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<E> implements Stack<E> {
|
||||
protected Node<E> 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<E> v = new Node<E>(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<E> 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<Integer> A = new NodeStack<Integer>();
|
||||
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
|
||||
11
net/datastructures/NonEmptyTreeException.java
Normal file
11
net/datastructures/NonEmptyTreeException.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
12
net/datastructures/Position.java
Normal file
12
net/datastructures/Position.java
Normal file
@@ -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<E> {
|
||||
/** Return the element stored at this position. */
|
||||
E element();
|
||||
}
|
||||
//end#fragment All
|
||||
50
net/datastructures/PositionList.java
Normal file
50
net/datastructures/PositionList.java
Normal file
@@ -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<E> extends Iterable<E> {
|
||||
//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<E> first();
|
||||
/** Returns the last node in the list. */
|
||||
public Position<E> last();
|
||||
/** Returns the node after a given node in the list. */
|
||||
public Position<E> next(Position<E> p)
|
||||
throws InvalidPositionException, BoundaryViolationException;
|
||||
/** Returns the node before a given node in the list. */
|
||||
public Position<E> prev(Position<E> 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<E> p, E e)
|
||||
throws InvalidPositionException;
|
||||
/** Inserts an element before the given node in the list. */
|
||||
public void addBefore(Position<E> p, E e)
|
||||
throws InvalidPositionException;
|
||||
/** Removes a node from the list, returning the element stored there. */
|
||||
public E remove(Position<E> p) throws InvalidPositionException;
|
||||
/** Replaces the element stored at the given node, returning old element. */
|
||||
public E set(Position<E> p, E e) throws InvalidPositionException;
|
||||
//end#fragment List
|
||||
//begin#fragment Positions
|
||||
/** Returns an iterable collection of all the nodes in the list. */
|
||||
public Iterable<Position<E>> positions();
|
||||
//end#fragment Positions
|
||||
//begin#fragment Iterator
|
||||
/** Returns an iterator of all the elements in the list. */
|
||||
public Iterator<E> iterator();
|
||||
//end#fragment Iterator
|
||||
//begin#fragment Tail
|
||||
}
|
||||
//end#fragment Tail
|
||||
17
net/datastructures/PriorityQueue.java
Normal file
17
net/datastructures/PriorityQueue.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package net.datastructures;
|
||||
|
||||
//begin#fragment PriorityQueue
|
||||
/** Interface for the priority queue ADT */
|
||||
public interface PriorityQueue<K,V> {
|
||||
/** 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<K,V> min() throws EmptyPriorityQueueException;
|
||||
/** Inserts a key-value pair and return the entry created. */
|
||||
public Entry<K,V> insert(K key, V value) throws InvalidKeyException;
|
||||
/** Removes and returns an entry with minimum key. */
|
||||
public Entry<K,V> removeMin() throws EmptyPriorityQueueException;
|
||||
}
|
||||
//end#fragment PriorityQueue
|
||||
43
net/datastructures/Queue.java
Normal file
43
net/datastructures/Queue.java
Normal file
@@ -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<E> {
|
||||
/**
|
||||
* 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
|
||||
219
net/datastructures/RBTree.java
Normal file
219
net/datastructures/RBTree.java
Normal file
@@ -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<K,V>
|
||||
extends BinarySearchTree<K,V> implements Dictionary<K,V> {
|
||||
public RBTree() { super(); }
|
||||
public RBTree(Comparator<K> C) { super(C); }
|
||||
/** Nested class for the nodes of a red-black tree */
|
||||
protected static class RBNode<K,V> extends BTNode<Entry<K,V>> {
|
||||
protected boolean isRed; // we add a color field to a BTNode
|
||||
RBNode() {/* default constructor */}
|
||||
/** Preferred constructor */
|
||||
RBNode(Entry<K,V> element, BTPosition<Entry<K,V>> parent,
|
||||
BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> 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<Entry<K,V>> createNode(Entry<K,V> element,
|
||||
BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left,
|
||||
BTPosition<Entry<K,V>> right) {
|
||||
return new RBNode<K,V>(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<K,V> insert(K k, V x) throws InvalidKeyException {
|
||||
Entry<K,V> toReturn = super.insert(k, x);
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> posZ) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> 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<K,V> remove(Entry<K,V> ent) throws InvalidEntryException {
|
||||
Entry<K,V> toReturn = super.remove(ent);
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> posR) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> position) {
|
||||
return ((RBNode) position).isRed();
|
||||
}
|
||||
|
||||
/** Returns whether the former parent of a node was red. */
|
||||
private boolean wasParentRed(Position<Entry<K,V>> 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<Entry<K,V>> position){
|
||||
if (isExternal(left(position))
|
||||
&& isExternal(right(position)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Colors a node red. */
|
||||
protected void setRed(Position<Entry<K,V>> position) {
|
||||
((RBNode) position).makeRed();
|
||||
}
|
||||
|
||||
/** Colors a node black. */
|
||||
protected void setBlack(Position<Entry<K,V>> position) {
|
||||
((RBNode) position).makeBlack();
|
||||
}
|
||||
|
||||
/** Sets the color of a node.
|
||||
* @param color <tt>true</tt> to color the node red, <tt>false</tt>
|
||||
* to color the node black*/
|
||||
protected void setColor(Position<Entry<K,V>> position, boolean color) {
|
||||
((RBNode) position).setColor(color);
|
||||
}
|
||||
|
||||
/** Returns a red child of a node. */
|
||||
protected Position<Entry<K,V>> redChild(Position<Entry<K,V>> position) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> position){
|
||||
if (isPosRed(left(position)) || isPosRed(right(position)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the colors of <tt>a</tt> and <tt>b</tt> if they are
|
||||
* different and returns whether <tt>a</tt> was red.
|
||||
*/
|
||||
protected boolean swapColor(Position<Entry<K,V>> a, Position<Entry<K,V>> 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<Entry<K,V>> swapPos, Position<Entry<K,V>> remPos){
|
||||
swapColor(remPos, swapPos);
|
||||
swapElements(swapPos, remPos);
|
||||
}
|
||||
}
|
||||
225
net/datastructures/RBTreeMap.java
Normal file
225
net/datastructures/RBTreeMap.java
Normal file
@@ -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<K,V>
|
||||
extends BinarySearchTreeMap<K,V> implements Map<K,V> {
|
||||
public RBTreeMap() { super(); }
|
||||
public RBTreeMap(Comparator<K> C) { super(C); }
|
||||
/** Nested class for the nodes of a red-black tree */
|
||||
protected static class RBNode<K,V> extends BTNode<Entry<K,V>> {
|
||||
protected boolean isRed; // we add a color field to a BTNode
|
||||
RBNode() {/* default constructor */}
|
||||
/** Preferred constructor */
|
||||
RBNode(Entry<K,V> element, BTPosition<Entry<K,V>> parent,
|
||||
BTPosition<Entry<K,V>> left, BTPosition<Entry<K,V>> 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<Entry<K,V>> createNode(Entry<K,V> element,
|
||||
BTPosition<Entry<K,V>> parent, BTPosition<Entry<K,V>> left,
|
||||
BTPosition<Entry<K,V>> right) {
|
||||
return new RBNode<K,V>(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<Entry<K,V>> 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<Entry<K,V>> posZ) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> 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<Entry<K,V>> 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<Entry<K,V>> posR) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> position) {
|
||||
return ((RBNode) position).isRed();
|
||||
}
|
||||
|
||||
/** Returns whether the former parent of a node was red. */
|
||||
private boolean wasParentRed(Position<Entry<K,V>> 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<Entry<K,V>> position){
|
||||
if (isExternal(left(position))
|
||||
&& isExternal(right(position)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Colors a node red. */
|
||||
protected void setRed(Position<Entry<K,V>> position) {
|
||||
((RBNode) position).makeRed();
|
||||
}
|
||||
|
||||
/** Colors a node black. */
|
||||
protected void setBlack(Position<Entry<K,V>> position) {
|
||||
((RBNode) position).makeBlack();
|
||||
}
|
||||
|
||||
/** Sets the color of a node.
|
||||
* @param color <tt>true</tt> to color the node red, <tt>false</tt>
|
||||
* to color the node black*/
|
||||
protected void setColor(Position<Entry<K,V>> position, boolean color) {
|
||||
((RBNode) position).setColor(color);
|
||||
}
|
||||
|
||||
/** Returns a red child of a node. */
|
||||
protected Position<Entry<K,V>> redChild(Position<Entry<K,V>> position) {
|
||||
Position<Entry<K,V>> 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<Entry<K,V>> position){
|
||||
if (isPosRed(left(position)) || isPosRed(right(position)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the colors of <tt>a</tt> and <tt>b</tt> if they are
|
||||
* different and returns whether <tt>a</tt> was red.
|
||||
*/
|
||||
protected boolean swapColor(Position<Entry<K,V>> a, Position<Entry<K,V>> 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<Entry<K,V>> swapPos, Position<Entry<K,V>> remPos){
|
||||
swapColor(remPos, swapPos);
|
||||
swapElements(swapPos, remPos);
|
||||
}
|
||||
}
|
||||
17
net/datastructures/Sequence.java
Normal file
17
net/datastructures/Sequence.java
Normal file
@@ -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<E>
|
||||
extends Deque<E>, IndexList<E>, PositionList<E> {
|
||||
/** Returns the position containing the element at the given index. */
|
||||
public Position<E> atIndex(int r) throws BoundaryViolationException;
|
||||
/** Returns the index of the element stored at the given position. */
|
||||
public int indexOf(Position<E> p) throws InvalidPositionException;
|
||||
}
|
||||
//end#fragment Sequence
|
||||
254
net/datastructures/Sort.java
Normal file
254
net/datastructures/Sort.java
Normal file
@@ -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 <E> void mergeSort (PositionList<E> in, Comparator<E> c) {
|
||||
int n = in.size();
|
||||
if (n < 2)
|
||||
return; // the in list is already sorted in this case
|
||||
// divide
|
||||
PositionList<E> in1 = new NodePositionList<E>();
|
||||
PositionList<E> in2 = new NodePositionList<E>();
|
||||
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 <E> void merge(PositionList<E> in1, PositionList<E> in2,
|
||||
Comparator<E> c, PositionList<E> 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 <E> void mergeSort(E[] orig, Comparator<E> 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 <E> void merge(E[] in, E[] out, Comparator<E> 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 <E> void quickSort(PositionList<E> in, Comparator<E> c) {
|
||||
if (in.size() <= 1)
|
||||
return;
|
||||
E pivot = in.remove(in.last());
|
||||
PositionList<E> lesser = new NodePositionList<E>();
|
||||
PositionList<E> equal = new NodePositionList<E>();
|
||||
PositionList<E> greater = new NodePositionList<E>();
|
||||
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 <E> void quickSort (E[] s, Comparator<E> 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 <E> void quickSortStep (E[] s, Comparator<E> 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<Integer> c = new DefaultComparator<Integer>();
|
||||
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<Integer> C = new NodePositionList<Integer>();
|
||||
PositionList<Integer> D = new NodePositionList<Integer>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
117
net/datastructures/SortedListPriorityQueue.java
Normal file
117
net/datastructures/SortedListPriorityQueue.java
Normal file
@@ -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<K,V> implements PriorityQueue<K,V> {
|
||||
protected PositionList<Entry<K,V>> entries;
|
||||
protected Comparator<K> c;
|
||||
protected Position<Entry<K,V>> actionPos; // variable used by subclasses
|
||||
/** Inner class for entries */
|
||||
protected static class MyEntry<K,V> implements Entry<K,V> {
|
||||
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<Entry<K,V>>();
|
||||
c = new DefaultComparator<K>();
|
||||
}
|
||||
/** Creates the priority queue with the given comparator. */
|
||||
public SortedListPriorityQueue (Comparator<K> comp) {
|
||||
entries = new NodePositionList<Entry<K,V>>();
|
||||
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<Entry<K,V>> list, Comparator<K> comp) {
|
||||
entries = list;
|
||||
c = comp;
|
||||
}
|
||||
/** Sets the comparator for this priority queue.
|
||||
* @throws IllegalStateException if priority queue is not empty */
|
||||
public void setComparator(Comparator<K> 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<K,V> 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<K,V> insert (K k, V v) throws InvalidKeyException {
|
||||
checkKey(k); // auxiliary key-checking method (could throw exception)
|
||||
Entry<K,V> entry = new MyEntry<K,V>(k, v);
|
||||
insertEntry(entry); // auxiliary insertion method
|
||||
return entry;
|
||||
}
|
||||
/** Auxiliary method used for insertion. */
|
||||
protected void insertEntry(Entry<K,V> 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<Entry<K,V>> 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<K,V> 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
|
||||
44
net/datastructures/Stack.java
Normal file
44
net/datastructures/Stack.java
Normal file
@@ -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<E> {
|
||||
/**
|
||||
* 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
|
||||
41
net/datastructures/Tree.java
Normal file
41
net/datastructures/Tree.java
Normal file
@@ -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<E> {
|
||||
/** 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<E> iterator();
|
||||
/** Returns an iterable collection of the the nodes. */
|
||||
public Iterable<Position<E>> positions();
|
||||
/** Replaces the element stored at a given node. */
|
||||
public E replace(Position<E> v, E e)
|
||||
throws InvalidPositionException;
|
||||
/** Returns the root of the tree. */
|
||||
public Position<E> root() throws EmptyTreeException;
|
||||
/** Returns the parent of a given node. */
|
||||
public Position<E> parent(Position<E> v)
|
||||
throws InvalidPositionException, BoundaryViolationException;
|
||||
/** Returns an iterable collection of the children of a given node. */
|
||||
public Iterable<Position<E>> children(Position<E> v)
|
||||
throws InvalidPositionException;
|
||||
/** Returns whether a given node is internal. */
|
||||
public boolean isInternal(Position<E> v)
|
||||
throws InvalidPositionException;
|
||||
/** Returns whether a given node is external. */
|
||||
public boolean isExternal(Position<E> v)
|
||||
throws InvalidPositionException;
|
||||
/** Returns whether a given node is the root of the tree. */
|
||||
public boolean isRoot(Position<E> v)
|
||||
throws InvalidPositionException;
|
||||
}
|
||||
//end#fragment Tree
|
||||
39
net/datastructures/TreeNode.java
Normal file
39
net/datastructures/TreeNode.java
Normal file
@@ -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<E> implements TreePosition<E> {
|
||||
private E element; // element stored at this node
|
||||
private TreePosition<E> parent; // adjacent node
|
||||
private PositionList<Position<E>> children; // children nodes
|
||||
//end#fragment TNode
|
||||
/** Default constructor */
|
||||
public TreeNode() { }
|
||||
//begin#fragment TNode
|
||||
/** Main constructor */
|
||||
public TreeNode(E element, TreePosition<E> parent,
|
||||
PositionList<Position<E>> 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<Position<E>> getChildren() { return children; }
|
||||
/** Sets the right child of this position */
|
||||
public void setChildren(PositionList<Position<E>> c) { children=c; }
|
||||
/** Returns the parent of this position */
|
||||
public TreePosition<E> getParent() { return parent; }
|
||||
/** Sets the parent of this position */
|
||||
public void setParent(TreePosition<E> v) { parent=v; }
|
||||
}
|
||||
//end#fragment TNode
|
||||
18
net/datastructures/TreePosition.java
Normal file
18
net/datastructures/TreePosition.java
Normal file
@@ -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<E> extends Position<E> { // inherits element()
|
||||
public void setElement(E o);
|
||||
public PositionList<Position<E>> getChildren();
|
||||
public void setChildren(PositionList<Position<E>> c);
|
||||
public TreePosition<E> getParent();
|
||||
public void setParent(TreePosition<E> v);
|
||||
}
|
||||
//end#fragment TPos
|
||||
6
net/datastructures/Vertex.java
Normal file
6
net/datastructures/Vertex.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package net.datastructures;
|
||||
/**
|
||||
* An interface for a vertex of a graph.
|
||||
* @author Roberto Tamassia
|
||||
*/
|
||||
public interface Vertex<E> extends DecorablePosition<E> { }
|
||||
Reference in New Issue
Block a user