diff --git a/.idea/misc.xml b/.idea/misc.xml
index 07115cd..05b1176 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/FlightRoutesGraph.java b/src/FlightRoutesGraph.java
new file mode 100644
index 0000000..1d5cc72
--- /dev/null
+++ b/src/FlightRoutesGraph.java
@@ -0,0 +1,109 @@
+import edu.greenriver.sdev333.BSTSet;
+import edu.greenriver.sdev333.MathSet;
+import edu.greenriver.sdev333.HashSet;
+
+/**
+ * Created in class 3/13/23, Ken coding
+ *
+ * printlns added by me
+ *
+ * Importing interface MathSet - can we use this for testing?
+ */
+public class FlightRoutesGraph {
+
+ // two sets needed to model the graph
+ // 1. a set of vertices (points, nodes) - airports
+ // 2. a set of edges (connections, lines, relationships) - routes between airports
+
+ private class Edge {
+ private String node1;
+ private String node2;
+
+ public Edge(String from, String to) {
+ node1 = from;
+ node2 = to;
+ }
+ }
+
+ private MathSet nodes; // set of nodes
+
+ private MathSet edges; // set of edges
+
+ //Commented out so Main class would compile
+ public FlightRoutesGraph() {
+ nodes = new BSTSet<>();
+ edges = new HashSet<>(); // must use HashSet here as edges are not comparable
+ }
+
+ public void addNode(String city) {
+ nodes.add(city);
+ }
+
+ public void addEdge(String city1, String city2) {
+ Edge connection = new Edge(city1, city2);
+ edges.add(connection);
+ }
+
+ /*
+ Edge Set = {
+ ORD, JFK
+ JFK, MCO
+ DEN, PHX
+ LAS, DEN
+ DFW, ORD
+ ATL, JFK
+ }
+
+ IF we are looking for cities connected to Denver, we are looking for 'Adjacency, i.e. neighbors.
+ */
+
+ /**
+ * Return cities that are neigbors to given city. There can be more than
+ * one neighbor, so should return a Set, i.e. MathSet of Strings/neighbors
+ *
+ * @param city
+ */
+ public MathSet getNeighbors(String city) {
+ // create an empty set to hold the results
+ MathSet neighbors = new BSTSet<>();
+
+ // loop through edges and check if city is
+ // in either node1 or node2
+ for (Edge e: edges.keys()) {
+ if (e.node1.equals(city)) {
+ neighbors.add(e.node2);
+ }
+ else if (e.node2.equals(city)) {
+ neighbors.add(e.node1);
+ }
+ }
+
+ return neighbors;
+ }
+
+ public static void main(String[] args) {
+ FlightRoutesGraph g = new FlightRoutesGraph();
+
+ // add all the cities first (nodes)
+ g.addNode("JFK");
+ g.addNode("ORD");
+ g.addNode("ATL");
+ g.addNode("MCO");
+ g.addNode("DEN");
+
+ // add connections beween cities
+ g.addEdge("ATL", "MCO");
+ g.addEdge("JFK", "MCO");
+ g.addEdge("DEN", "ORD");
+ g.addEdge("ORD", "ATL");
+ // more to go if you want
+
+ // look for direct flights from JFK
+ MathSet directFromJFK = g.getNeighbors("JFK");
+ MathSet directFromATL = g.getNeighbors("ATL");
+
+ System.out.println(directFromJFK);
+ System.out.println(directFromATL);
+
+ }
+}
diff --git a/src/Main.java b/src/Main.java
index 3e59c38..a53bfa8 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,5 +1,61 @@
+import edu.greenriver.sdev333.BSTSet;
+import edu.greenriver.sdev333.MathSet;
+import edu.greenriver.sdev333.HashSet;
+
+/**
+ * Used to test our set implementations. Each class is declared twice to
+ * test against itself. Uncomment/comment the appropriate lines to test
+ * a specific class (BSTSet or SeparateChainingHashSet)
+ *
+ * @author Paul Woods
+ */
public class Main {
public static void main(String[] args) {
- System.out.println("Hello world!");
+
+ // Test BSTSet structures
+ MathSet test1 = new BSTSet<>();
+ MathSet test2 = new BSTSet<>();
+
+ // Test SeparateChainingHashTable structures
+ //MathSet test1 = new HashSet<>();
+ //MathSet test2 = new HashSet<>();
+
+ System.out.println("isEmpty() - should be true: " + test1.isEmpty());
+ System.out.println("size() - should be 0: " + test1.size());
+
+ System.out.println("adding 6 keys to set ... ");
+
+ test1.add("g");
+ test1.add("q");
+ test1.add("r");
+ test1.add("b");
+ test1.add("k");
+ test1.add("c");
+
+ System.out.println("size() - should be 6: " + test1.size());
+ System.out.println("isEmpty() - should be false: " + test1.isEmpty());
+ System.out.println();
+ System.out.println("contains('r') - should be true: " + test1.contains("r"));
+ System.out.println("contains('a') - should be false: " + test1.contains("a"));
+ System.out.println("contains('c') - should be true: " + test1.contains("c"));
+ System.out.println("contains('z') - should be false: " + test1.contains("z"));
+ System.out.println();
+
+ System.out.println("Creating 2nd set to test MathSet interface functions");
+
+ test2.add("z");
+ test2.add("a");
+ test2.add("b"); // in test1
+ test2.add("q"); // in test1
+ test2.add("j");
+ test2.add("c"); // in test1
+
+ System.out.println("contents of test1: " + test1.toString());
+ System.out.println("contents of test2: " + test2.toString());
+ System.out.println();
+ System.out.println("test1.union(test2): " + test1.union(test2));
+ System.out.println("test1.intersection(test2): " + test1.intersection(test2));
+ System.out.println("test1.difference(test2): " + test1.difference(test2));
+
}
}
\ No newline at end of file
diff --git a/src/edu/greenriver/sdev333/BSTSet.java b/src/edu/greenriver/sdev333/BSTSet.java
new file mode 100644
index 0000000..a7ba75a
--- /dev/null
+++ b/src/edu/greenriver/sdev333/BSTSet.java
@@ -0,0 +1,270 @@
+package edu.greenriver.sdev333;
+
+/**
+ * This class implements the MathSet interface, mimicking a mathematical
+ * set while employing a Binary Tree in its implementation. This allows
+ * the BSTSet to be ordered, and requires the Keys that are stored to
+ * implement the Comparable interface. Some code was written during
+ * class w/ Ken.
+ *
+ * @author Paul Woods
+ * @param
+ */
+public class BSTSet> implements MathSet {
+
+ // Used code from BST class as reference ...
+
+ // node helper class
+ private class Node {
+ private KeyType key;
+ private Node left;
+ private Node right;
+ private int N;
+
+ public Node(KeyType key, int N) {
+ this.key = key;
+ this.N = N;
+ }
+ }
+
+ private Node root;
+ private int size;
+
+ /**
+ * Puts the specified key into the set.
+ *
+ * @param key key to be added into the set
+ */
+ @Override
+ public void add(KeyType key) {
+ // in case the tree is empty, having = allows us to save/start the tree
+ if (!contains(key)) {
+ root = add(root, key);
+ ++size;
+ }
+ }
+
+
+ private Node add(Node n, KeyType key) {
+ // we are where we are supposed to be
+ if (n == null) {
+ // create a new node
+ return new Node(key, 1);
+ }
+
+ int cmp = key.compareTo(n.key);
+ // n will be < 0 if key < current
+ // n = 0 if key == current
+ // n > 0 if key > current
+
+ if (cmp < 0) {
+ // go left
+ n.left = add(n.left, key);
+ } else if (cmp > 0) {
+ // go right
+ n.right = add(n.right, key);
+ }
+
+ // update the node's N, number of nodes in subtree
+ // size of left + size of right + self
+ // resets size N as works way back up the stack
+ int l = 0;
+ int r = 0;
+ if (n.right != null)
+ r = n.right.N;
+ if (n.left != null)
+ l = n.left.N;
+
+ n.N = l + r + 1; // add N values from left and right nodes (if exist)
+
+ return n;
+ }
+
+ /**
+ * Is the key in the set?
+ *
+ * @param key key to check
+ * @return true if key is in the set, false otherwise
+ */
+ @Override
+ public boolean contains(KeyType key) {
+ return contains(root, key);
+ }
+
+ /*
+ * Recursive helper method for contains(KeyType)
+ */
+ private boolean contains(Node current, KeyType key) {
+
+ // if we are at a point that is null and have not found key
+ if (current == null) {
+ return false;
+ }
+
+ // compare current key value to key looking for
+ int compare = key.compareTo(current.key);
+
+ if (compare == 0) {
+ return true;
+ } else if (compare < 0) {
+ return contains(current.left, key);
+ } else {
+ return contains(current.right, key);
+ }
+ }
+
+ /**
+ * Is the set empty?
+ *
+ * @return true if the set is empty, false otherwise
+ */
+ @Override
+ public boolean isEmpty() {
+ return (root == null);
+ }
+
+ /**
+ * Number of keys in the set
+ *
+ * @return number of keys in the set.
+ */
+ @Override
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Determine the union of this set with another specified set.
+ * Returns A union B, where A is this set, B is other set.
+ * A union B = {key | A.contains(key) OR B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * @param other specified set to union
+ * @return the union of this set with other
+ */
+ @Override
+ public MathSet union(MathSet other) {
+
+ MathSet temp = new BSTSet<>();
+
+ for (KeyType key: this.keys()) {
+ temp.add(key);
+ }
+
+ for (KeyType key: other.keys()) {
+ temp.add(key);
+ }
+
+ return temp;
+ }
+
+ /**
+ * Determine the intersection of this set with another specified set.
+ * Returns A intersect B, where A is this set, B is other set.
+ * A intersect B = {key | A.contains(key) AND B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * @param other specified set to intersect
+ * @return the intersection of this set with other
+ */
+ @Override
+ public MathSet intersection(MathSet other) {
+ // cycle through set A
+ // determine if key is in set B
+ // if true, add key to temp set
+
+ MathSet temp = new BSTSet<>();
+
+ for (KeyType key: this.keys()) {
+ if (other.contains(key)) {
+ temp.add(key);
+ }
+ }
+
+ return temp;
+ }
+
+ /**
+ * Determine the difference of this set with another specified set.
+ * Returns A difference B, where A is this set, B is other set.
+ * A difference B = {key | A.contains(key) AND !B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * {a,b,r,c,e} - {c,e,d,u,f} = {a,b,r} only
+ * will cycle through 1st set, checking for elements in 2nd set
+ * if are not present in 2nd set, add to result set
+ *
+ * @param other specified set to difference
+ * @return the difference of this set with other
+ */
+ @Override
+ public MathSet difference(MathSet other) {
+
+ // create an empty set that will hold the result
+ MathSet result = new BSTSet();
+
+ for (KeyType key: this.keys()) {
+ if (!other.contains(key)) {
+ result.add(key);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Overridden toString() method to output this list
+ * in a presentable manner. Used for testing in
+ * the Main class as well.
+ * @return
+ */
+ @Override
+ public String toString() {
+
+ String s = "{";
+ for (KeyType key: keys()) {
+ s += key + ", ";
+ }
+
+ s = s.substring(0, s.length() - 2);
+ s += "}";
+
+ return s;
+
+ }
+
+ /**
+ * Retrieves a collection of all the keys in this set.
+ *
+ * @return a collection of all keys in this set
+ */
+ @Override
+ public Iterable keys() {
+ // new empty queue to hold results
+ Queue queue = new Queue<>();
+
+ // start the recursion
+ inorder(root, queue);
+
+ return queue;
+ }
+
+ // Helper method for keys(), recursively finds list of
+ // keys inside tree
+ private void inorder(Node current, Queue q) {
+ if (current == null) {
+ // do nothing - intentionally blank
+ return;
+ }
+
+ // left subtree
+ inorder(current.left, q);
+
+ // add self to queue
+ q.enqueue(current.key);
+
+ // right subtree
+ inorder(current.right, q);
+ }
+
+}
diff --git a/src/edu/greenriver/sdev333/HashSet.java b/src/edu/greenriver/sdev333/HashSet.java
new file mode 100644
index 0000000..95b02c9
--- /dev/null
+++ b/src/edu/greenriver/sdev333/HashSet.java
@@ -0,0 +1,214 @@
+package edu.greenriver.sdev333;
+
+/**
+ * This class implements the MathSet interface, mimicking a mathematical
+ * set while employing an Array of LinkedLists in its implementation. This
+ * class is not ordered, and does not require its keys to implement any
+ * special interfaces. Some code implemented in class w/ Ken
+ *SeparateChainingHashTable
+ * @author Paul Woods
+ * @param
+ */
+public class HashSet implements MathSet {
+
+ private int M; // number of buckets
+ private LinkedList[] bucket; // lists that reside in each bucket
+ private int size;
+
+ /**
+ * Default constructor, defaults to a bucket list size
+ * of 997 elements.
+ */
+ public HashSet() {
+ this(997); // call w/ a default prime # value, ensure more unique lists
+ }
+
+ /**
+ * Constructor, with M indicating number of buckets to allocate
+ * for.
+ * @param M
+ */
+ public HashSet(int M) {
+ this.M = M;
+
+ bucket = new LinkedList[M];
+
+ for (int i = 0; i < M; i++) {
+ bucket[i] = new LinkedList<>();
+ }
+ }
+
+ /*
+ * returns the array element and linked list to address
+ * when getting/putting/working-with this key value
+ */
+ private int hash(KeyType key) {
+ return (key.hashCode() & 0x7fffffff) % M;
+ }
+
+
+
+ /**
+ * Puts the specified key into the set.
+ *
+ * @param key key to be added into the set
+ */
+ @Override
+ public void add(KeyType key) {
+ if (!contains(key)) {
+ bucket[hash(key)].add(key);
+ ++size;
+ }
+ }
+
+ /**
+ * Is the key in the set?
+ *
+ * Utilizes the contains method from the LinkedList class
+ * @param key key to check
+ * @return true if key is in the set, false otherwise
+ */
+ @Override
+ public boolean contains(KeyType key) {
+
+ // return a LinkedList for the bucket corresponding to this key/hash
+ return bucket[hash(key)].contains(key);
+ }
+
+ /**
+ * Is the set empty?
+ *
+ * @return true if the set is empty, false otherwise
+ */
+ @Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Number of keys in the set
+ *
+ * @return number of keys in the set.
+ */
+ @Override
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Determine the union of this set with another specified set.
+ * Returns A union B, where A is this set, B is other set.
+ * A union B = {key | A.contains(key) OR B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * @param other specified set to union
+ * @return the union of this set with other
+ */
+ @Override
+ public MathSet union(MathSet other) {
+
+
+ MathSet temp = new HashSet<>();
+
+ for (KeyType key: this.keys()) {
+ temp.add(key);
+ }
+
+ for (KeyType key: other.keys()) {
+ temp.add(key);
+ }
+
+ return temp;
+ }
+
+ /**
+ * Determine the intersection of this set with another specified set.
+ * Returns A intersect B, where A is this set, B is other set.
+ * A intersect B = {key | A.contains(key) AND B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * @param other specified set to intersect
+ * @return the intersection of this set with other
+ */
+ @Override
+ public MathSet intersection(MathSet other) {
+ // cycle through set A
+ // determine if key is in set B
+ // if true, add key to temp set
+
+ MathSet temp = new HashSet<>();
+
+ for (KeyType key: this.keys()) {
+ if (other.contains(key)) {
+ temp.add(key);
+ }
+ }
+
+ return temp;
+ }
+
+ /**
+ * Determine the difference of this set with another specified set.
+ * Returns A difference B, where A is this set, B is other set.
+ * A difference B = {key | A.contains(key) AND !B.contains(key)}.
+ * Does not change the contents of this set or the other set.
+ *
+ * @param other specified set to difference
+ * @return the difference of this set with other
+ */
+ @Override
+ public MathSet difference(MathSet other) {
+
+ // create an empty set that will hold the result
+ MathSet result = new HashSet();
+
+ for (KeyType key: this.keys()) {
+ if (!other.contains(key)) {
+ result.add(key);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Retrieves a collection of all the keys in this set.
+ *
+ * @return a collection of all keys in this set
+ */
+ @Override
+ public Iterable keys() {
+ Queue queue = new Queue<>();
+
+ // cycle through array of Lists, bucket
+ for (int i = 0; i < M; i++) {
+ // cycle through LinkedList
+ for (int a = 0; a < bucket[i].size(); a++) {
+ queue.enqueue(bucket[i].get(a));
+ }
+ }
+
+ return queue;
+ }
+
+ /**
+ * Overridden toString() method to output this list
+ * in a presentable manner. Used for testing in
+ * the Main class as well.
+ * @return
+ */
+ @Override
+ public String toString() {
+
+ String s = "{";
+ for (KeyType key: keys()) {
+ s += key + ", ";
+ }
+
+ s = s.substring(0, s.length() - 2);
+ s += "}";
+
+ return s;
+
+ }
+}
diff --git a/src/edu/greenriver/sdev333/LinkedList.java b/src/edu/greenriver/sdev333/LinkedList.java
new file mode 100644
index 0000000..a2e8523
--- /dev/null
+++ b/src/edu/greenriver/sdev333/LinkedList.java
@@ -0,0 +1,593 @@
+package edu.greenriver.sdev333;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Final Project Note: The code for this class is 95% copied from
+ * code written in the ImplementingLists project, specifically the
+ * DoublyLinkedList class.
+ *
+ * @author Paul Woods
+ */
+
+public class LinkedList{
+
+ private Node head;
+ private int size;
+
+ // helper/inner class
+ private class Node {
+ ItemType data;
+ Node next;
+ Node previous;
+ }
+
+ /*
+ * Test w/ for-each statemenet
+ */
+ private class OurCustomIterator implements Iterator {
+
+ private Node iHead;
+
+ public OurCustomIterator() {
+ //iHead = DoublyLinkedList.this.head;
+ iHead = head;
+ }
+ @Override
+ public boolean hasNext() {
+ // Ken tested for if (currentPostition != null) ... but he had reversed the two lines in next() as well
+ //return iHead.next != null;
+ if ((iHead != null) && iHead.next != null)
+ return true;
+ return false;
+ }
+
+ /*
+ * Ken had iHead.next and result = lines reversed
+ */
+ @Override
+ public ItemType next() {
+ iHead = iHead.next;
+ ItemType result = (ItemType) iHead.data;
+ return result;
+ }
+ }
+
+ // geeksforgeeks.org/difference-between-an-iterator-and-listiterator-in-java/
+ private class OurListIterator implements ListIterator {
+
+ private Node iHead;
+ private Node priorNode;
+
+ public OurListIterator() {
+ iHead = head;
+ }
+ @Override
+ public boolean hasNext() {
+ return iHead.next != null;
+ }
+
+ @Override
+ public ItemType next() {
+ iHead = iHead.next;
+ ItemType result = (ItemType) iHead.data;
+ priorNode = iHead;
+ return result;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ //return iHead.previous != null;
+ //return iHead.previous != null;
+ return iHead != null;
+ }
+
+ @Override
+ public ItemType previous() {
+ //iHead = iHead.previous;
+ //ItemType result = (ItemType) iHead.data;
+ ItemType result = (ItemType) iHead.data;
+ //if (iHead.previous != null)
+ iHead = iHead.previous;
+ priorNode = iHead;
+ return result;
+ }
+
+ @Override
+ public int nextIndex() {
+ if (iHead.next == null)
+ return size();
+
+ ItemType next = next();
+ Node node = head;
+ int i = 0;
+
+ while (node.next != null) {
+ node = node.next;
+ i++;
+ if (node.next.data.equals(next)) {
+ return i;
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public int previousIndex() {
+ if (iHead.previous == null)
+ return -1;
+
+ ItemType prev = (ItemType) iHead.previous.data;
+ Node node = head;
+ int i = -1;
+
+ while (node.next != null) {
+ node = node.next; // will be head node w/ index 0 to start
+ i++;
+ if (node.data.equals(prev)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override
+ public void remove() {
+ // both prior and next nodes ARE NOT null
+ if (priorNode.previous != null && priorNode.next != null) {
+ priorNode.previous.next = priorNode.next; // prior nodes' next value = next node
+ priorNode.next.previous = priorNode.previous;
+ }
+ // both prior and next nodes ARE null (single item in list)
+ else if (priorNode.previous == null && priorNode.next == null) {
+ iHead.next = null;
+ }
+ // prior only IS NULL (1st item in list)
+ else if (priorNode.previous == null) {
+ iHead = priorNode.next;
+ }
+ // next only IS NULL (last item in list)
+ else if (priorNode.next == null) {
+ priorNode.next = null;
+ }
+ }
+
+ @Override
+ public void set(ItemType itemType) {
+
+ }
+
+ @Override
+ public void add(ItemType itemType) {
+
+ }
+ }
+
+ /*
+ * Return a pointer to the last element in the linked-list
+ */
+ private Node getLastElement() {
+ if (size == 0) {
+ return null;
+ } else {
+ Node n = head;
+ while (n.next != null) {
+ n = n.next;
+ }
+ return n;
+ }
+ }
+
+ /*
+ * could have been left inside getElementN, but broken into a separate method for use
+ * by other methods if required
+ */
+ private void validateIndex(int index) {
+ if ((index >= size) || (index < 0))
+ throw new IndexOutOfBoundsException();
+ }
+
+ /*
+ * Return element at index n (not the data in that element)
+ */
+ private Node getElementN(int index) {
+
+ validateIndex(index);
+
+ Node n = head;
+ int i = -1;
+
+ while (n.next != null) {
+ i++;
+ n = n.next;
+ if (i == index) {
+ //System.out.println("data, " + n.data);
+ return n;
+ }
+ }
+
+ // we shouldn't be here ...
+ throw new NullPointerException();
+ }
+
+ public LinkedList() {
+ // A new list contains no elemenets, so its head is null
+ head = null;
+ size = 0;
+ }
+
+ /**
+ * Returns the number of items in this collection.
+ *
+ * @return the number of items in this collection
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Returns true if this collection contains no items.
+ *
+ * @return true if this collection contains no items
+ */
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Returns true if this collection contains the specified item.
+ *
+ * @param item items whose presence in this collection is to be tested
+ * @return true if this collection contains the specified item
+ * @throws NullPointerException if the specified item is null
+ * and this collection does not permit null items
+ */
+ public boolean contains(ItemType item) {
+
+ if (size == 0)
+ return false;
+
+ return indexOf(item) != -1;
+ }
+
+ /**
+ * Returns an iterator over the elements in this collection.
+ *
+ * @return an Iterator over the elements in this collection
+ */
+ public Iterator iterator() {
+ return new OurCustomIterator<>();
+ }
+
+ /**
+ * Adds the specified item to the collection.
+ *
+ * @param item item to be added to the collection
+ * @throws NullPointerException if the specified item is null
+ * and this collection does not permit null items
+ */
+ public void add(ItemType item) {
+
+ if (head == null) { // Add new 1st item, item.previous = null
+ head = new Node();
+ head.next = new Node();
+ head.next.data = item;
+ } else {
+ Node currentLast = getLastElement();
+
+ currentLast.next = new Node();
+ currentLast.next.data = item;
+ currentLast.next.previous = currentLast;
+ }
+
+ ++size;
+ }
+
+ /**
+ * Compares the specified object (a collection) with this collection for equality.
+ *
+ * Equal only if the lists are the same size, and each node equals the matching
+ * node in the alternate list.
+ *
+ * @param obj object to be compared for equality with this collection
+ * @return true if the specified other object is equal to this collection
+ */
+ @Override
+ public boolean equals(Object obj) {
+ // https://docs.oracle.com/javase/7/docs/api/java/util/AbstractList.html#equals(java.lang.Object)
+ // object is not null, and it matches this class type
+ if (obj != null && obj.getClass() == this.getClass()) {
+
+ LinkedList list = (LinkedList) obj;
+
+ if (this.size != list.size())
+ return false;
+
+ ListIterator litA = this.listIterator();
+ ListIterator litB = list.listIterator();
+ while (litA.hasNext()) {
+ if (!litA.next().equals(litB.next()))
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Removes a single instance of the specified item from this collection,
+ * if it is present.
+ *
+ * @param item item to be removed from this collection, if present
+ * @throws NullPointerException if the specified item is null
+ * and this collection does not permit null items
+ */
+ public void remove(ItemType item) {
+ if (item == null)
+ throw new NullPointerException();
+
+ Node n = head;
+
+ // 1st Node is treated differently as it has no valid previous
+ if (n.next.data.equals(item)) {
+ n.next = n.next.next;
+ n.next.previous = null;
+ --size;
+ }
+ else {
+ while (n.next != null) {
+ n = n.next;
+ if (n.data.equals(item)) {
+ if (n.next != null)
+ n.next.previous = n.previous; // assign 'previous' for following node to prior node
+ n.previous.next = n.next; // assign 'next' for prior node to n.next
+ --size;
+ return;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Removes all items from this collection.
+ * The collection will be empty after this method returns.
+ */
+ public void clear() {
+ head = null;
+ size = 0;
+ }
+
+ /**
+ * Returns true if this collection contains all the items
+ * in the specified other collection.
+ *
+ * @param otherCollection collection to be checked for containment in this collection
+ * @return true if this collection contains all the items
+ * in the specified other collection
+ */
+ public boolean containsAll(Collection extends ItemType> otherCollection) {
+ // Cycle through otherCollection, and when find an element from that
+ // collection here, remove it. If at some point we do not find one of those
+ // elements, return false. If we make it through the list, return true
+ for (ItemType i: otherCollection) {
+ if (!this.contains(i))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds all the items in this specified other collection to this collection.
+ *
+ * @param otherCollection collection containing items to be added to this collection
+ */
+ public void addAll(Collection extends ItemType> otherCollection) {
+ if (otherCollection != null) {
+ for (ItemType i: otherCollection) {
+ this.add(i);
+ }
+ }
+ }
+
+ /**
+ * Removes all of this collection's items that are also contained in the
+ * specified other collection. After this call returns, this collection will
+ * contain no elements in common with the specified other collection.
+ *
+ * @param otherCollection collection containing elements to be removed
+ * from this collection
+ */
+ public void removeAll(Collection extends ItemType> otherCollection) {
+ if (otherCollection != null) {
+ for (ItemType i: otherCollection) {
+ this.remove(i);
+ }
+ }
+ }
+
+ /**
+ * Retains only the items in this collection that are contained in the
+ * specified other collection. In other words, removes from this collection
+ * all of its items that are not contained in the specified other collection
+ *
+ * @param otherCollection collection containing elements to be retained in
+ * this collection
+ */
+ /*
+ public void retainAll(Collection extends ItemType> otherCollection) {
+ // Create a value-copy of current list
+ LinkedList listCopy = new LinkedList<>();
+ for (ItemType i: this) {
+ listCopy.add(i);
+ }
+
+ // remove items in otherCollection from listCopy
+ // this leaves us with an inverted view of the list
+ listCopy.removeAll(otherCollection);
+
+ // now remove listCopy items from originalList
+ this.removeAll(listCopy);
+ }*/
+
+ /**
+ * Returns the item at the specified position in this list
+ *
+ * @param index index of the item to return
+ * @return the item at the specified position in this list
+ * @throws IndexOutOfBoundsException if this index is out of range
+ * (index < 0 || index >= size())
+ */
+ public ItemType get(int index) {
+ return getElementN(index).data;
+ }
+
+ /**
+ * Replaces the item at the specified position in this list
+ * with the specified item
+ *
+ * @param index index of the item to replace
+ * @param item item to be stored at the specified position
+ * @throws NullPointerException if the specified item is null
+ * and this list does not permit null elements
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= size())
+ */
+ public void set(int index, ItemType item) {
+ if (item == null)
+ throw new NullPointerException();
+
+ Node i = getElementN(index);
+ i.data = item;
+ }
+
+ /**
+ * Inserts the specified item at the specified position in this list.
+ * Shifts the item currently at that position (if any) and any subsequent
+ * items to the right.
+ *
+ * @param index index at which the specified item is to be inserted
+ * @param item item to be inserted
+ * @throws NullPointerException if the specified item is null
+ * and this list does not permit null elements
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= size())
+ */
+ public void add(int index, ItemType item) {
+ if (item == null)
+ throw new NullPointerException();
+
+ Node i = getElementN(index); // current element at index
+ Node n = new Node(); // new node to be inserted
+ n.data = item;
+ if (index != 0)
+ n.previous = i.previous; // previous value for new node
+ n.next = i; // next value for new node
+ i.previous.next = n; // next value for old prior node
+ i.previous = n; // previous value for old node
+
+ ++size;
+ }
+
+ /**
+ * Removes the element at the specified position in this list.
+ * Shifts any subsequent items to the left.
+ *
+ * @param index the index of the item to be removed
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= size())
+ */
+ public void remove(int index) {
+ Node i = getElementN(index);
+
+ if (index == 0) {
+ head.next = i.next;
+ i.next.previous = null;
+ } else {
+ i.previous.next = i.next;
+ i.next.previous = i.previous;
+ }
+
+ --size;
+ }
+
+ /**
+ * Returns the index of the first occurrence of the specified item
+ * in this list, or -1 if this list does not contain the item.
+ *
+ * @param item the item to search for
+ * @return the index of the first occurrence of the specified item
+ * in this list, or -1 if this list does not contain the item
+ * @throws NullPointerException if the specified item is null and this
+ * list does not permit null items
+ */
+ public int indexOf(ItemType item) {
+ if (item == null)
+ throw new NullPointerException();
+
+ Node n = head;
+ int i = -1;
+
+ while (n.next != null) {
+ i++;
+ n = n.next;
+ if (n.data.equals(item))
+ return i;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the index of the last occurrence of the specified item
+ * in this list, or -1 if this list does not contain the item.
+ *
+ * @param item the item to search for
+ * @return the index of the first occurrence of the specified item
+ * in this list, or -1 if this list does not contain the item
+ * @throws NullPointerException if the specified item is null and this
+ * list does not permit null items
+ */
+ public int lastIndexOf(ItemType item) {
+
+ if (item == null)
+ throw new NullPointerException();
+
+ Node n = getLastElement();
+ int index = size - 1;
+
+ while (true) {
+
+ if (n.data.equals(item))
+ return index;
+
+ if (n.previous != null) {
+ n = n.previous;
+ //System.out.println("cycling through last-index, looking for " + item + ", have " + n.data);
+ --index;
+ } else {
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns a list iterator over the elements in this list
+ * (in proper sequence).
+ *
+ * @return a list iterator over the elements in this list
+ * (in proper sequence)
+ */
+ public ListIterator listIterator() {
+ return new OurListIterator<>();
+ }
+}
\ No newline at end of file
diff --git a/src/edu/greenriver/sdev333/MathSet.java b/src/edu/greenriver/sdev333/MathSet.java
index 4273aba..af520f6 100644
--- a/src/edu/greenriver/sdev333/MathSet.java
+++ b/src/edu/greenriver/sdev333/MathSet.java
@@ -5,6 +5,8 @@
* Sets have a collection of unique elements (keys) - no duplicate keys allowed.
* Set operations include contains, size, union, intersection, and difference.
* Set complement and element (key) deletion is not supported by this API.
+ *
+ * @author Paul Woods, interface from Ken Hang
* @param
*/
public interface MathSet {