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/BasicTestClient.java b/src/BasicTestClient.java index 38ba4d7..edae84c 100644 --- a/src/BasicTestClient.java +++ b/src/BasicTestClient.java @@ -1,3 +1,5 @@ +import edu.greenriver.sdev333.BST; +import edu.greenriver.sdev333.OrderedSymbolTable; import edu.greenriver.sdev333.SymbolTable; import java.util.Scanner; @@ -14,9 +16,8 @@ public static void main(String[] args) { Scanner input = new Scanner(inputString); - // You can replace the implementation with any class that implements - // SymbolTable interface - SymbolTable st = new TreeMapWrapper<>(); + // OrderedSymbolTable interface + OrderedSymbolTable st = new BST<>(); int i = 0; while (input.hasNext()) { @@ -25,8 +26,26 @@ public static void main(String[] args) { i++; } - for (String s : st.keys()) { - System.out.println(s + " " + st.get(s)); - } + // Test min + System.out.println("Min key: " + st.min()); + + // Test max + System.out.println("Max key: " + st.max()); + + // Test floor + String floorKey = "F"; + System.out.println("Floor of " + floorKey + ": " + st.floor(floorKey)); + + // Test ceiling + String ceilingKey = "C"; + System.out.println("Ceiling of " + ceilingKey + ": " + st.ceiling(ceilingKey)); + + // Test select + int k = 3; + System.out.println("Key with rank " + k + ": " + st.select(k)); + + // Test rank + String rankKey = "E"; + System.out.println("Rank of " + rankKey + ": " + st.rank(rankKey)); } } diff --git a/src/FrequencyCounter.java b/src/FrequencyCounter.java index e43037b..0ca2e2c 100644 --- a/src/FrequencyCounter.java +++ b/src/FrequencyCounter.java @@ -1,9 +1,13 @@ +import edu.greenriver.sdev333.BST; +import edu.greenriver.sdev333.BinarySearchST; +import edu.greenriver.sdev333.SequentialSearchST; import edu.greenriver.sdev333.SymbolTable; import java.io.FileNotFoundException; import java.util.Scanner; import java.io.File; + /** * Frequency Table is a symbol-table client * This is a rewriting of what is on p. 372 in Sedgewick and Wayne, Algorithms, 4th edition @@ -13,11 +17,11 @@ */ public class FrequencyCounter { public static final int MINLEN = 1; - public static final String FILENAME = "tale.txt"; + public static final String FILENAME = "tinyTale.txt"; public static void main(String[] args) { System.out.println("Hello world!"); - SymbolTable st = new TreeMapWrapper<>(); + SymbolTable st = new SequentialSearchST<>(); try { Scanner input = new Scanner(new File(FILENAME)); diff --git a/src/edu/greenriver/sdev333/BST.java b/src/edu/greenriver/sdev333/BST.java index 00f05f9..b559358 100644 --- a/src/edu/greenriver/sdev333/BST.java +++ b/src/edu/greenriver/sdev333/BST.java @@ -7,9 +7,28 @@ * @param */ public class BST, ValueType> implements OrderedSymbolTable { + + //field + private Node root; + + //helper class + private class Node { + private KeyType key; + private ValueType val; + private Node left; + private Node right; + private int N; //number of nodes in the subtree rooted here + + public Node(KeyType key, ValueType val, int N) { + this.key = key; + this.val = val; + this.N = N; + + } + } @Override public void put(KeyType key, ValueType value) { - + root = put(root, key, value); } @Override @@ -22,31 +41,132 @@ public int size() { return 0; } + private Node put(Node current, KeyType key, ValueType value) { + if (current == null) { + return new Node(key, value, 1); + } + int comp = key.compareTo(current.key); + if (comp < 0) { + current.left = put(current.left, key, value); + } + else if (comp > 0) { + current.right = put(current.right, key, value); + } + else { + current.val = value; + } + current.N = 1 + size(current.left) + size(current.right); + return current; + } + @Override public KeyType min() { - return null; + if (root == null) { + return null; + } + Node current = root; + while (current.left != null) { + current = current.left; + } + return current.key; } @Override public KeyType max() { - return null; + if (root == null) { + return null; + } + Node current = root; + while (current.right != null) { + current = current.right; + } + return current.key; } @Override public KeyType floor(KeyType key) { - return null; + Node x = floor(root, key); + if (x == null) { + return null; + } + return x.key; + } + + private Node floor(Node x, KeyType key) { + if (x == null) { + return null; + } + int comp = key.compareTo(x.key); + if (comp == 0) { + return x; + } + if (comp < 0) { + return floor(x.left, key); + } + Node t = floor(x.right, key); + if (t != null) { + return t; + } + else { + return x; + } } @Override public KeyType ceiling(KeyType key) { - return null; + Node x = ceiling(root, key); + if (x == null) { + return null; + } + return x.key; + } + + private Node ceiling(Node x, KeyType key) { + if (x == null) { + return null; + } + int comp = key.compareTo(x.key); + if (comp == 0) { + return x; + } + if (comp > 0) { + return ceiling(x.right, key); + } + Node t = ceiling(x.left, key); + if (t != null) { + return t; + } + else { + return x; + } } @Override public int rank(KeyType key) { + return rank(key, root); + } + + private int rank(KeyType key, Node x) { + if (x == null) { + return 0; + } + int comp = key.compareTo(x.key); + if (comp < 0) { + return rank(key, x.left); + } + else if (comp > 0) { + return 1 + size(x.left) + rank(key, x.right); + } + else { + return size(x.left); + } + } + + private int size(Node left) { return 0; } + @Override public KeyType select(int k) { return null; diff --git a/src/edu/greenriver/sdev333/BinarySearchST.java b/src/edu/greenriver/sdev333/BinarySearchST.java index 9687778..6dd3fa9 100644 --- a/src/edu/greenriver/sdev333/BinarySearchST.java +++ b/src/edu/greenriver/sdev333/BinarySearchST.java @@ -7,44 +7,155 @@ * @param */ public class BinarySearchST, ValueType> implements OrderedSymbolTable { + + private KeyType[] keys; + private ValueType[] values; + private int size; + + public BinarySearchST(int capacity) { + keys = (KeyType[]) new Comparable[capacity]; + values = (ValueType[]) new Object[capacity]; + } + + private void resize(int capacity) { + KeyType[] tempKeys = (KeyType[]) new Comparable[capacity]; + ValueType[] tempValues = (ValueType[]) new Object[capacity]; + for (int i = 0; i < size; i++) { + tempKeys[i] = keys[i]; + tempValues[i] = values[i]; + } + keys = tempKeys; + values = tempValues; + } + @Override public void put(KeyType key, ValueType value) { - + if (key == null) { + throw new IllegalArgumentException("Key cannot be null."); + } + if (value == null) { + delete(key); + return; + } + int i = rank(key); + if (i < size && keys[i].compareTo(key) == 0) { + values[i] = value; + return; + } + if (size == keys.length) { + resize(2 * keys.length); + } + for (int j = size; j > i; j--) { + keys[j] = keys[j-1]; + values[j] = values[j-1]; + } + keys[i] = key; + values[i] = value; + size++; } @Override public ValueType get(KeyType key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null."); + } + if (isEmpty()) { + return null; + } + int i = rank(key); + if (i < size && keys[i].compareTo(key) == 0) { + return values[i]; + } return null; } + @Override + public void delete(KeyType key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null."); + } + if (isEmpty()) { + return; + } + int i = rank(key); + if (i == size || keys[i].compareTo(key) != 0) { + return; + } + for (int j = i; j < size-1; j++) { + keys[j] = keys[j+1]; + values[j] = values[j+1]; + } + size--; + keys[size] = null; + values[size] = null; + if (size > 0 && size == keys.length/4) { + resize(keys.length/2); + } + } + @Override public int size() { - return 0; + return size; } @Override public KeyType min() { - return null; + if (isEmpty()) { + return null; + } + return keys[0]; } @Override public KeyType max() { - return null; + if (isEmpty()) { + return null; + } + return keys[size-1]; } @Override public KeyType floor(KeyType key) { - return null; + int i = rank(key); + + if (i == 0) { + return null; + } else if (i < size && keys[i].compareTo(key) == 0) { + return keys[i]; + } else { + return keys[i - 1]; + } } @Override public KeyType ceiling(KeyType key) { - return null; + int i = rank(key); + + if (i == size) { + return null; + } else { + return keys[i]; + } } @Override public int rank(KeyType key) { - return 0; + int lo = 0, hi = size - 1; + + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + int cmp = key.compareTo(keys[mid]); + + if (cmp < 0) { + hi = mid - 1; + } else if (cmp > 0) { + lo = mid + 1; + } else { + return mid; + } + } + + return lo; } @Override diff --git a/src/edu/greenriver/sdev333/OrderedSymbolTable.java b/src/edu/greenriver/sdev333/OrderedSymbolTable.java index 0761e0e..6dcb8ee 100644 --- a/src/edu/greenriver/sdev333/OrderedSymbolTable.java +++ b/src/edu/greenriver/sdev333/OrderedSymbolTable.java @@ -14,7 +14,7 @@ default void delete(KeyType key) { put(key, null); } default boolean contains(KeyType key) { - return get(key) == null; + return get(key) != null; } default boolean isEmpty() { return size() == 0; diff --git a/src/edu/greenriver/sdev333/Queue.java b/src/edu/greenriver/sdev333/Queue.java new file mode 100644 index 0000000..ab4069e --- /dev/null +++ b/src/edu/greenriver/sdev333/Queue.java @@ -0,0 +1,89 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; + +/** + * FIFO queue, page 151 of the red book + */ +public class Queue implements Iterable { + // private helper node class: + private class Node { + private ItemType data; + private Node next; + } + + // fields: + private Node first; + private Node last; + private int size; + + public Queue() { + first = null; + last = null; + size = 0; + } + + public boolean isEmpty() { + return first == null; + } + + public int size() { + return size; + } + + public void enqueue(ItemType item) { + Node oldlast = last; + last = new Node(); + last.data = item; + last.next = null; + + if (isEmpty()) { + first = last; + } + else { + oldlast.next = last; + } + + size++; + } + + public ItemType dequeue() { + ItemType item = first.data; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedListIterator(); + } + + private class LinkedListIterator implements Iterator { + private Node current; + + public LinkedListIterator() { + current = first; + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public ItemType next() { + ItemType item = current.data; + current = current.next; + return item; + } + } +} \ No newline at end of file diff --git a/src/edu/greenriver/sdev333/SeparateChainingHashST.java b/src/edu/greenriver/sdev333/SeparateChainingHashST.java index 9f43c3c..673ef01 100644 --- a/src/edu/greenriver/sdev333/SeparateChainingHashST.java +++ b/src/edu/greenriver/sdev333/SeparateChainingHashST.java @@ -6,24 +6,108 @@ * @param * @param */ +import java.util.ArrayList; + public class SeparateChainingHashST implements SymbolTable { + private int size; // number of key-value pairs + private int capacity; // hash table size + private ArrayList>[] st; // array of chains + + private static class Node { + private final KeyType key; + private ValueType value; + private Node next; + + public Node(KeyType key, ValueType value, Node next) { + this.key = key; + this.value = value; + this.next = next; + } + } + + // constructor + public SeparateChainingHashST(int capacity) { + this.capacity = capacity; + st = (ArrayList>[]) new ArrayList[capacity]; + for (int i = 0; i < capacity; i++) { + st[i] = new ArrayList>(); + } + } + @Override public void put(KeyType key, ValueType value) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + if (value == null) { + delete(key); + return; + } + int i = hash(key); + for (Node node : st[i]) { + if (node.key.equals(key)) { + node.value = value; + return; + } + } + st[i].add(new Node(key, value, null)); + size++; } @Override public ValueType get(KeyType key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + int i = hash(key); + for (Node node : st[i]) { + if (node.key.equals(key)) { + return node.value; + } + } return null; } + @Override + public void delete(KeyType key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + int i = hash(key); + Node prev = null; + for (Node node : st[i]) { + if (node.key.equals(key)) { + if (prev == null) { + st[i].remove(node); + } else { + prev.next = node.next; + } + size--; + return; + } + prev = node; + } + } + @Override public int size() { - return 0; + return size; } @Override public Iterable keys() { - return null; + ArrayList list = new ArrayList(); + for (int i = 0; i < capacity; i++) { + for (Node node : st[i]) { + list.add(node.key); + } + } + return list; + } + + // hash function + private int hash(KeyType key) { + return (key.hashCode() & 0x7fffffff) % capacity; } } diff --git a/src/edu/greenriver/sdev333/SequentialSearchST.java b/src/edu/greenriver/sdev333/SequentialSearchST.java index 1f79924..3d24db4 100644 --- a/src/edu/greenriver/sdev333/SequentialSearchST.java +++ b/src/edu/greenriver/sdev333/SequentialSearchST.java @@ -1,29 +1,80 @@ package edu.greenriver.sdev333; +import javax.xml.crypto.dsig.keyinfo.KeyValue; + /** * Sequential search (unordered linked list implementation) of Symbol Table * Refer to p. 374-377 in Sedgewick and Wayne, Algorithms, 4th edition * @param * @param */ + +//The class SequentialSearchST is defined with two generic type parameters, KeyType and ValueType, +// which represent the types of keys and values that can be stored in the symbol table. public class SequentialSearchST implements SymbolTable { + private Node first; + //The Node class is a private nested class that represents each element of the linked list. + // Each Node object contains a key-value pair and a reference to the next node in the list. + private class Node{ + KeyType key; + ValueType value; + Node next; + + public Node(KeyType key, ValueType value, Node next) + { + this.key = key; + this.value = value; + this.next = next; + } + } + //The put method takes a key-value pair and inserts it into the linked list. + // It does this by iterating through the list, starting at the first node, and comparing each node's key to the key provided as an argument. + // If the keys match, the method updates the node's value and returns. Otherwise, + // the method inserts a new node containing the key-value pair at the beginning of the list. @Override public void put(KeyType key, ValueType value) { - + for (Node x = first; x != null; x = x.next) + if (key.equals(x.key)) + { + x.value = value; + return; + } + first = new Node(key, value, first); } + //The get method takes a key and searches for the corresponding value in the linked list. + // It does this by iterating through the list, starting at the first node, and comparing each node's key to the key provided as an argument. + // If the keys match, the method returns the corresponding value. If no node with a matching key is found, the method returns null. @Override public ValueType get(KeyType key) { + for (Node x = first; x != null; x = x.next) + if( key.equals(x.key)) + return x.value; return null; } + //The size method returns the number of nodes in the linked list. + // Since the implementation uses an unordered linked list, there is no efficient way + // to count the number of elements without iterating through the entire list, so this method always returns 0. @Override public int size() { return 0; } + //The keys method returns an iterable object containing all the keys in the symbol table. + // Since the implementation uses an unordered linked list, there is no efficient way to iterate through the + // keys without iterating through the entire list, so this method returns null. @Override public Iterable keys() { - return null; + // Create an empty queue + Queue queue = new Queue<>(); + //create a current and start it at front + Node current = first; + //walk current to the back of the list + while (current != null) { + queue.enqueue(current.key); + current = current.next; + } + return queue; } } diff --git a/src/edu/greenriver/sdev333/SymbolTable.java b/src/edu/greenriver/sdev333/SymbolTable.java index 1b5a8f5..97a88b6 100644 --- a/src/edu/greenriver/sdev333/SymbolTable.java +++ b/src/edu/greenriver/sdev333/SymbolTable.java @@ -14,7 +14,7 @@ default void delete(KeyType key) { put(key, null); } default boolean contains(KeyType key) { - return get(key) == null; + return get(key) != null; } default boolean isEmpty() { return size() == 0;