From 6b72f86edbba7ee4727fbcf2cddd255f3ec357eb Mon Sep 17 00:00:00 2001 From: Paul W Date: Wed, 8 Mar 2023 14:16:21 -0800 Subject: [PATCH 1/8] comment test --- .idea/misc.xml | 2 +- .idea/vcs.xml | 6 ++++++ src/edu/greenriver/sdev333/MathSet.java | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .idea/vcs.xml 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/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 { From 1b3362bdf4f25b503cf1deb46e9d81a3c0c58b94 Mon Sep 17 00:00:00 2001 From: Paul W Date: Wed, 8 Mar 2023 14:53:49 -0800 Subject: [PATCH 2/8] working on MathSet --- src/edu/greenriver/sdev333/BSTSet.java | 142 +++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/edu/greenriver/sdev333/BSTSet.java diff --git a/src/edu/greenriver/sdev333/BSTSet.java b/src/edu/greenriver/sdev333/BSTSet.java new file mode 100644 index 0000000..937f9e5 --- /dev/null +++ b/src/edu/greenriver/sdev333/BSTSet.java @@ -0,0 +1,142 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; + +public class BSTSet implements MathSet { + + // TODO: union method, add this and other to results set, done + + // TODO: intersect, walk through next, what exists in other, add to result set + + // + + // TODO: Use 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; + + /** + * Puts the specified key into the set. + * + * @param key key to be added into the set + */ + @Override + public void add(Object key) { + + } + + /** + * 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(Object key) { + return false; + } + + /** + * Is the set empty? + * + * @return true if the set is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return false; + } + + /** + * Number of keys in the set + * + * @return number of keys in the set. + */ + @Override + public int size() { + return 0; + } + + /** + * 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) { + return null; + } + + /** + * 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) { + return null; + } + + /** + * 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) { + + // TODO: implement keys method for this to work, take from BST + + // create an empty set that will hold the result + MathSet result = new BSTSet(); + + // iterate (walk) through all items in this + Iterator itr = (Iterator) this.keys(); + + while (itr.hasNext()) { + KeyType currentKey = itr.next(); + if (!other.contains(currentKey)) { + result.add(currentKey); + } + } + + 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() { + return null; + } +} From 1e7b849927de3f52aea2d7db8e0fde976a3c3121 Mon Sep 17 00:00:00 2001 From: Paul Woods Date: Mon, 13 Mar 2023 15:16:55 -0700 Subject: [PATCH 3/8] continued work on BSTSet --- .idea/misc.xml | 2 +- src/FlightRoutesGraph.java | 104 +++++++++++++++++++++++++ src/edu/greenriver/sdev333/BSTSet.java | 15 +++- 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 src/FlightRoutesGraph.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 05b1176..07115cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/src/FlightRoutesGraph.java b/src/FlightRoutesGraph.java new file mode 100644 index 0000000..e8003ac --- /dev/null +++ b/src/FlightRoutesGraph.java @@ -0,0 +1,104 @@ +import edu.greenriver.sdev333.BSTSet; +import edu.greenriver.sdev333.MathSet; + +import java.util.HashSet; + +/** + * Created in class 3/13/23, Ken coding + * + * 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 + + 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"); + + } +} diff --git a/src/edu/greenriver/sdev333/BSTSet.java b/src/edu/greenriver/sdev333/BSTSet.java index 937f9e5..df993ba 100644 --- a/src/edu/greenriver/sdev333/BSTSet.java +++ b/src/edu/greenriver/sdev333/BSTSet.java @@ -2,7 +2,7 @@ import java.util.Iterator; -public class BSTSet implements MathSet { +public class BSTSet, ValueType> implements MathSet { // TODO: union method, add this and other to results set, done @@ -33,8 +33,17 @@ public Node(KeyType key, int N) { * @param key key to be added into the set */ @Override - public void add(Object key) { + public void add(KeyType key) { + add(key, root); + } + + private void add(KeyType key, Node n) { + if (key.compareTo(n.key) > 0) { + if (n.right == null) { + n.right = new Node(key, 0); + } + } } /** @@ -44,7 +53,7 @@ public void add(Object key) { * @return true if key is in the set, false otherwise */ @Override - public boolean contains(Object key) { + public boolean contains(KeyType key) { return false; } From 06bca75a1bcb68aed5984ac6fca1c194ebc492bd Mon Sep 17 00:00:00 2001 From: Paul Woods Date: Mon, 13 Mar 2023 22:25:50 -0700 Subject: [PATCH 4/8] Finished BSTSet and SeparateChainingHashTable classes, tested both inside Main.java. --- src/FlightRoutesGraph.java | 4 +- src/Main.java | 116 +++- src/edu/greenriver/sdev333/BSTSet.java | 189 ++++-- src/edu/greenriver/sdev333/LinkedList.java | 593 ++++++++++++++++++ .../sdev333/SeparateChainingHashTable.java | 216 +++++++ 5 files changed, 1080 insertions(+), 38 deletions(-) create mode 100644 src/edu/greenriver/sdev333/LinkedList.java create mode 100644 src/edu/greenriver/sdev333/SeparateChainingHashTable.java diff --git a/src/FlightRoutesGraph.java b/src/FlightRoutesGraph.java index e8003ac..2ea2d83 100644 --- a/src/FlightRoutesGraph.java +++ b/src/FlightRoutesGraph.java @@ -27,12 +27,12 @@ public Edge(String from, String 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); } diff --git a/src/Main.java b/src/Main.java index 3e59c38..d94258b 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,5 +1,119 @@ +import edu.greenriver.sdev333.BSTSet; +import edu.greenriver.sdev333.MathSet; +import edu.greenriver.sdev333.SeparateChainingHashTable; +import java.security.Key; + +/** + * Used to test our set implementations. The tests are divided into two + * sections, one per class (BSTSet first, then SeparateChainingHashSet next) + * @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 test3 = new SeparateChainingHashTable<>(); + MathSet test4 = new SeparateChainingHashTable<>(); + + + /* + * Code to test BSTSet.java - it works! + */ + System.out.println("----------------------------------------------"); + System.out.println("TESTING BSTSet Class -------------------------"); + System.out.println("----------------------------------------------"); + 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)); + + /* + * End BSTSet testing code + */ + + /* + * Code to test SeparateChainingHashTable.java + */ + System.out.println(); + System.out.println(); + System.out.println("----------------------------------------------"); + System.out.println("TESTING SeparateChainingHashTable Class ------"); + System.out.println("----------------------------------------------"); + System.out.println("isEmpty() - should be true: " + test3.isEmpty()); + System.out.println("size() - should be 0: " + test3.size()); + + System.out.println("adding 6 keys to set ... "); + + test3.add("g"); + test3.add("q"); + test3.add("r"); + test3.add("b"); + test3.add("k"); + test3.add("c"); + + System.out.println("size() - should be 6: " + test3.size()); + System.out.println("isEmpty() - should be false: " + test3.isEmpty()); + System.out.println(); + System.out.println("contains('r') - should be true: " + test3.contains("r")); + System.out.println("contains('a') - should be false: " + test3.contains("a")); + System.out.println("contains('c') - should be true: " + test3.contains("c")); + System.out.println("contains('z') - should be false: " + test3.contains("z")); + System.out.println(); + + System.out.println("Creating 2nd set to test MathSet interface functions"); + + test4.add("z"); + test4.add("a"); + test4.add("b"); // in test3 + test4.add("q"); // in test3 + test4.add("j"); + test4.add("c"); // in test3 + + System.out.println("contents of test3: " + test3.toString()); + System.out.println("contents of test4: " + test4.toString()); + System.out.println(); + System.out.println("test3.union(test4): " + test3.union(test4)); + System.out.println("test3.intersection(test4): " + test3.intersection(test4)); + System.out.println("test3.difference(test4): " + test3.difference(test4)); + /* + * End SeparateChainingHashTable testing code + */ + } } \ No newline at end of file diff --git a/src/edu/greenriver/sdev333/BSTSet.java b/src/edu/greenriver/sdev333/BSTSet.java index df993ba..a7ba75a 100644 --- a/src/edu/greenriver/sdev333/BSTSet.java +++ b/src/edu/greenriver/sdev333/BSTSet.java @@ -1,16 +1,18 @@ package edu.greenriver.sdev333; -import java.util.Iterator; +/** + * 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 { -public class BSTSet, ValueType> implements MathSet { - - // TODO: union method, add this and other to results set, done - - // TODO: intersect, walk through next, what exists in other, add to result set - - // - - // TODO: Use code from BST class as reference ... + // Used code from BST class as reference ... // node helper class private class Node { @@ -26,6 +28,7 @@ public Node(KeyType key, int N) { } private Node root; + private int size; /** * Puts the specified key into the set. @@ -34,16 +37,47 @@ public Node(KeyType key, int N) { */ @Override public void add(KeyType key) { - add(key, root); + // in case the tree is empty, having = allows us to save/start the tree + if (!contains(key)) { + root = add(root, key); + ++size; + } } - private void add(KeyType key, Node n) { - if (key.compareTo(n.key) > 0) { - if (n.right == null) { - n.right = new Node(key, 0); - } + 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; } /** @@ -54,7 +88,29 @@ private void add(KeyType key, Node n) { */ @Override public boolean contains(KeyType key) { - return false; + 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); + } } /** @@ -64,7 +120,7 @@ public boolean contains(KeyType key) { */ @Override public boolean isEmpty() { - return false; + return (root == null); } /** @@ -74,7 +130,7 @@ public boolean isEmpty() { */ @Override public int size() { - return 0; + return size; } /** @@ -87,8 +143,19 @@ public int size() { * @return the union of this set with other */ @Override - public MathSet union(MathSet other) { - return null; + 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; } /** @@ -101,8 +168,20 @@ public MathSet union(MathSet other) { * @return the intersection of this set with other */ @Override - public MathSet intersection(MathSet other) { - return null; + 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; } /** @@ -119,33 +198,73 @@ public MathSet intersection(MathSet other) { * @return the difference of this set with other */ @Override - public MathSet difference(MathSet other) { - - // TODO: implement keys method for this to work, take from BST + public MathSet difference(MathSet other) { // create an empty set that will hold the result MathSet result = new BSTSet(); - // iterate (walk) through all items in this - Iterator itr = (Iterator) this.keys(); - - while (itr.hasNext()) { - KeyType currentKey = itr.next(); - if (!other.contains(currentKey)) { - result.add(currentKey); + 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() { - return null; + 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/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/SeparateChainingHashTable.java b/src/edu/greenriver/sdev333/SeparateChainingHashTable.java new file mode 100644 index 0000000..2909110 --- /dev/null +++ b/src/edu/greenriver/sdev333/SeparateChainingHashTable.java @@ -0,0 +1,216 @@ +package edu.greenriver.sdev333; + +import java.security.Key; + +/** + * 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 + * + * @author Paul Woods + * @param + */ +public class SeparateChainingHashTable 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 SeparateChainingHashTable() { + 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 SeparateChainingHashTable(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 SeparateChainingHashTable<>(); + + 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 SeparateChainingHashTable<>(); + + 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 SeparateChainingHashTable(); + + 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; + + } +} From 4fa6b0131f0ec55cb3c80aaab525ece146dd3438 Mon Sep 17 00:00:00 2001 From: Paul Woods Date: Tue, 14 Mar 2023 00:13:25 -0700 Subject: [PATCH 5/8] Cleaned up Main class --- src/FlightRoutesGraph.java | 13 +++++-- src/Main.java | 75 +++++--------------------------------- 2 files changed, 20 insertions(+), 68 deletions(-) diff --git a/src/FlightRoutesGraph.java b/src/FlightRoutesGraph.java index 2ea2d83..2b5cb8a 100644 --- a/src/FlightRoutesGraph.java +++ b/src/FlightRoutesGraph.java @@ -1,11 +1,14 @@ import edu.greenriver.sdev333.BSTSet; import edu.greenriver.sdev333.MathSet; +import edu.greenriver.sdev333.SeparateChainingHashTable; import java.util.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 { @@ -27,12 +30,13 @@ public Edge(String from, String to) { private MathSet nodes; // set of nodes private MathSet edges; // set of edges -/* Commented out so Main class would compile + + //Commented out so Main class would compile public FlightRoutesGraph() { nodes = new BSTSet<>(); - edges = new HashSet<>(); // must use HashSet here as edges are not comparable + edges = new SeparateChainingHashTable<>(); // must use HashSet here as edges are not comparable } -*/ + public void addNode(String city) { nodes.add(city); } @@ -100,5 +104,8 @@ public static void main(String[] args) { 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 d94258b..17d09da 100644 --- a/src/Main.java +++ b/src/Main.java @@ -4,28 +4,25 @@ import java.security.Key; /** - * Used to test our set implementations. The tests are divided into two - * sections, one per class (BSTSet first, then SeparateChainingHashSet next) + * 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) { + + // Test BSTSet structures - MathSet test1 = new BSTSet<>(); - MathSet test2 = new BSTSet<>(); + //MathSet test1 = new BSTSet<>(); + //MathSet test2 = new BSTSet<>(); // Test SeparateChainingHashTable structures - MathSet test3 = new SeparateChainingHashTable<>(); - MathSet test4 = new SeparateChainingHashTable<>(); - + MathSet test1 = new SeparateChainingHashTable<>(); + MathSet test2 = new SeparateChainingHashTable<>(); - /* - * Code to test BSTSet.java - it works! - */ - System.out.println("----------------------------------------------"); - System.out.println("TESTING BSTSet Class -------------------------"); - System.out.println("----------------------------------------------"); System.out.println("isEmpty() - should be true: " + test1.isEmpty()); System.out.println("size() - should be 0: " + test1.size()); @@ -63,57 +60,5 @@ public static void main(String[] args) { System.out.println("test1.intersection(test2): " + test1.intersection(test2)); System.out.println("test1.difference(test2): " + test1.difference(test2)); - /* - * End BSTSet testing code - */ - - /* - * Code to test SeparateChainingHashTable.java - */ - System.out.println(); - System.out.println(); - System.out.println("----------------------------------------------"); - System.out.println("TESTING SeparateChainingHashTable Class ------"); - System.out.println("----------------------------------------------"); - System.out.println("isEmpty() - should be true: " + test3.isEmpty()); - System.out.println("size() - should be 0: " + test3.size()); - - System.out.println("adding 6 keys to set ... "); - - test3.add("g"); - test3.add("q"); - test3.add("r"); - test3.add("b"); - test3.add("k"); - test3.add("c"); - - System.out.println("size() - should be 6: " + test3.size()); - System.out.println("isEmpty() - should be false: " + test3.isEmpty()); - System.out.println(); - System.out.println("contains('r') - should be true: " + test3.contains("r")); - System.out.println("contains('a') - should be false: " + test3.contains("a")); - System.out.println("contains('c') - should be true: " + test3.contains("c")); - System.out.println("contains('z') - should be false: " + test3.contains("z")); - System.out.println(); - - System.out.println("Creating 2nd set to test MathSet interface functions"); - - test4.add("z"); - test4.add("a"); - test4.add("b"); // in test3 - test4.add("q"); // in test3 - test4.add("j"); - test4.add("c"); // in test3 - - System.out.println("contents of test3: " + test3.toString()); - System.out.println("contents of test4: " + test4.toString()); - System.out.println(); - System.out.println("test3.union(test4): " + test3.union(test4)); - System.out.println("test3.intersection(test4): " + test3.intersection(test4)); - System.out.println("test3.difference(test4): " + test3.difference(test4)); - /* - * End SeparateChainingHashTable testing code - */ - } } \ No newline at end of file From 411cadf1831e39ab214002024adc772b052e7eff Mon Sep 17 00:00:00 2001 From: Paul W Date: Wed, 15 Mar 2023 14:13:19 -0700 Subject: [PATCH 6/8] Renamed SeparateChainingHashTable to HashSet --- .idea/misc.xml | 2 +- .../sdev333/SeparateChainingHashTable.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) 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/src/edu/greenriver/sdev333/SeparateChainingHashTable.java b/src/edu/greenriver/sdev333/SeparateChainingHashTable.java index 2909110..cee2f37 100644 --- a/src/edu/greenriver/sdev333/SeparateChainingHashTable.java +++ b/src/edu/greenriver/sdev333/SeparateChainingHashTable.java @@ -7,11 +7,11 @@ * 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 SeparateChainingHashTable implements MathSet { +public class HashSet implements MathSet { private int M; // number of buckets private LinkedList[] bucket; // lists that reside in each bucket @@ -21,7 +21,7 @@ public class SeparateChainingHashTable implements MathSet { * Default constructor, defaults to a bucket list size * of 997 elements. */ - public SeparateChainingHashTable() { + public HashSet() { this(997); // call w/ a default prime # value, ensure more unique lists } @@ -30,7 +30,7 @@ public SeparateChainingHashTable() { * for. * @param M */ - public SeparateChainingHashTable(int M) { + public HashSet(int M) { this.M = M; bucket = new LinkedList[M]; @@ -110,7 +110,7 @@ public int size() { public MathSet union(MathSet other) { - MathSet temp = new SeparateChainingHashTable<>(); + MathSet temp = new HashSet<>(); for (KeyType key: this.keys()) { temp.add(key); @@ -138,7 +138,7 @@ public MathSet intersection(MathSet other) { // determine if key is in set B // if true, add key to temp set - MathSet temp = new SeparateChainingHashTable<>(); + MathSet temp = new HashSet<>(); for (KeyType key: this.keys()) { if (other.contains(key)) { @@ -162,7 +162,7 @@ public MathSet intersection(MathSet other) { public MathSet difference(MathSet other) { // create an empty set that will hold the result - MathSet result = new SeparateChainingHashTable(); + MathSet result = new HashSet(); for (KeyType key: this.keys()) { if (!other.contains(key)) { From 5df0c08a785c90a1328d7d08ae7f35ea0508e747 Mon Sep 17 00:00:00 2001 From: Paul W Date: Wed, 15 Mar 2023 14:14:42 -0700 Subject: [PATCH 7/8] Renamed SeparateChainingHashTable to HashSet, 2nd attempt --- src/FlightRoutesGraph.java | 6 ++---- src/Main.java | 8 +++----- .../{SeparateChainingHashTable.java => HashSet.java} | 2 -- 3 files changed, 5 insertions(+), 11 deletions(-) rename src/edu/greenriver/sdev333/{SeparateChainingHashTable.java => HashSet.java} (99%) diff --git a/src/FlightRoutesGraph.java b/src/FlightRoutesGraph.java index 2b5cb8a..1d5cc72 100644 --- a/src/FlightRoutesGraph.java +++ b/src/FlightRoutesGraph.java @@ -1,8 +1,6 @@ import edu.greenriver.sdev333.BSTSet; import edu.greenriver.sdev333.MathSet; -import edu.greenriver.sdev333.SeparateChainingHashTable; - -import java.util.HashSet; +import edu.greenriver.sdev333.HashSet; /** * Created in class 3/13/23, Ken coding @@ -34,7 +32,7 @@ public Edge(String from, String to) { //Commented out so Main class would compile public FlightRoutesGraph() { nodes = new BSTSet<>(); - edges = new SeparateChainingHashTable<>(); // must use HashSet here as edges are not comparable + edges = new HashSet<>(); // must use HashSet here as edges are not comparable } public void addNode(String city) { diff --git a/src/Main.java b/src/Main.java index 17d09da..353386e 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,7 +1,5 @@ -import edu.greenriver.sdev333.BSTSet; import edu.greenriver.sdev333.MathSet; -import edu.greenriver.sdev333.SeparateChainingHashTable; -import java.security.Key; +import edu.greenriver.sdev333.HashSet; /** * Used to test our set implementations. Each class is declared twice to @@ -20,8 +18,8 @@ public static void main(String[] args) { //MathSet test2 = new BSTSet<>(); // Test SeparateChainingHashTable structures - MathSet test1 = new SeparateChainingHashTable<>(); - MathSet test2 = new SeparateChainingHashTable<>(); + 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()); diff --git a/src/edu/greenriver/sdev333/SeparateChainingHashTable.java b/src/edu/greenriver/sdev333/HashSet.java similarity index 99% rename from src/edu/greenriver/sdev333/SeparateChainingHashTable.java rename to src/edu/greenriver/sdev333/HashSet.java index cee2f37..95b02c9 100644 --- a/src/edu/greenriver/sdev333/SeparateChainingHashTable.java +++ b/src/edu/greenriver/sdev333/HashSet.java @@ -1,7 +1,5 @@ package edu.greenriver.sdev333; -import java.security.Key; - /** * This class implements the MathSet interface, mimicking a mathematical * set while employing an Array of LinkedLists in its implementation. This From 4dbfa6b2e9f66c29d73985c24d96b86190a0d1e2 Mon Sep 17 00:00:00 2001 From: Paul W Date: Wed, 15 Mar 2023 14:18:13 -0700 Subject: [PATCH 8/8] final testing --- src/Main.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Main.java b/src/Main.java index 353386e..a53bfa8 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,3 +1,4 @@ +import edu.greenriver.sdev333.BSTSet; import edu.greenriver.sdev333.MathSet; import edu.greenriver.sdev333.HashSet; @@ -11,15 +12,13 @@ public class Main { public static void main(String[] args) { - - // Test BSTSet structures - //MathSet test1 = new BSTSet<>(); - //MathSet test2 = new BSTSet<>(); + MathSet test1 = new BSTSet<>(); + MathSet test2 = new BSTSet<>(); // Test SeparateChainingHashTable structures - MathSet test1 = new HashSet<>(); - MathSet test2 = new HashSet<>(); + //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());