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 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 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 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 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 {