diff --git a/.gitignore b/.gitignore
index 0338737..ea5f22e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,4 @@ hs_err_pid*
/Lab108-VenbergGE/nbproject/private/
/Lab108-VenbergGE/build/
/Lab108-VenbergGE/dist/
+/Lab109/build/
diff --git a/Lab109/src/ASCIITable.java b/Lab109/src/ASCIITable.java
new file mode 100644
index 0000000..4ceff25
--- /dev/null
+++ b/Lab109/src/ASCIITable.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2021 Gabriel Venberg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * utility library for nicely formatted ascii tables.
+ * @author Gabriel Venberg
+ */
+public class ASCIITable {
+
+ /**
+ * generates an ASCII table based on a 2d data array. the top level array is an array of rows.
+ * @param data 2d array containing data to put in table
+ * @param padding how much padding to put on each side of entries
+ * @param tableHeader string to put in the table header (may cause problems if extremely long)
+ * @param columnHeaders array of strings to put at the top of each column.
+ * @return
+ */
+ public static String render(Object data[][], int padding, String tableHeader, String[] columnHeaders) throws IllegalArgumentException {
+ int cols = calcNoCols(data);
+ if(cols!=columnHeaders.length){throw new IllegalArgumentException("must have equal number of column headers as columns!");}
+ int[] colWidths = calcColumnWidth(cols, data, columnHeaders);
+ //colWidths does not count padding or the | chars betwwen tables.
+ int width = sumOfArray(colWidths)+padding*cols*2+(cols-1);
+ String horizontalSpacer = assembleHorizontalSpacers(colWidths, padding, cols);
+ /*ok, so each cell will have the colwidth for the data, then padding for padding,
+ * then a | at the end. (plus 1 at the begginning of the table.
+ there will be 2 rows for each row of data (horizontal sep) plus a horizontal sep
+ at the end.
+ */
+ String string = horizontalSpacer+'\n';
+ //print table header
+ string=string+tableHeader(tableHeader, width)+"\n";
+ string = string+horizontalSpacer+"\n";
+ //print coumn headers
+ string=string+columnHeaderString(colWidths, padding, columnHeaders)+'\n';
+ //got everything set up, build the table row by row.
+ for(int i=0; i implements PriorityQueue {
+
+ //nested PQEntry class
+ protected static class PQEntry implements Entry {
+ private K k;
+ private V v;
+ public PQEntry(K key, V value){
+ k=key;
+ v=value;
+ }
+ //methods of entry interface
+ public K getKey(){return k;}
+ public V getValue(){return v;}
+ //utilites not exposed
+ protected void setKey(K key){k=key;}
+ protected void setValue(V value){v=value;}
+ }
+ //end of nested class
+
+ /** the comparator defining ordering of keys into the priority queue.*/
+ private Comparator comp;
+
+ /** Creates an empty priority queue using the given comparator to order keys. */
+ protected AbstractPriorityQueue(Comparator c){comp=c;}
+
+ /** creates an empty priority queue based on the natrual ordering of its keys */
+ protected AbstractPriorityQueue(){this(new DefaultComparator());}
+
+ /** method for comparing two entries according to the key*/
+ protected int compare(Entry a, Entry b){
+ return comp.compare(a.getKey(), b.getKey());
+ }
+
+ /** determines whether a key is valid*/
+ protected boolean checkKey(K key) throws IllegalArgumentException {
+ try{
+ return (comp.compare(key,key)==0); //see if the key can be compared
+ }catch(ClassCastException e){
+ throw new IllegalArgumentException("incompatable key");
+ }
+ }
+
+ /**tests whether the priority queue is empty*/
+ public boolean isEmpty(){return size()==0;}
+}
diff --git a/Lab109/src/Client.java b/Lab109/src/Client.java
new file mode 100644
index 0000000..ca990b8
--- /dev/null
+++ b/Lab109/src/Client.java
@@ -0,0 +1,122 @@
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Scanner;
+import javax.swing.JOptionPane;
+
+/*
+ * Copyright (C) 2021 Gabriel Venberg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received p copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ *
+ * @author Gabriel Venberg
+ */
+public class Client {
+ public static void main(String[] args){
+ String filePath = (String) JOptionPane.showInputDialog(null, "Enter the path of the file", "/home/toric/Downloads/words/words.txt");
+ File file = new File(filePath);
+ Scanner fileContents = null;
+ try {
+ fileContents = new Scanner(file);
+ } catch (FileNotFoundException ex) {
+ JOptionPane.showMessageDialog(null, "file does not exist.");
+ System.exit(1);
+ }
+
+ ArrayList words = new ArrayList<>();
+
+ while(fileContents.hasNext()){
+ words.add(fileContents.next());
+ }
+
+ String[][] hashData = new String[15][3];
+
+ for(int a=30; a<45; a++){
+ //tried using this using an array of buckets, it got... messy
+ HeapPriorityQueue hashes = new HeapPriorityQueue<>();
+ for(int i=0; i< words.size(); i++){
+ //the value doesnt matter
+ hashes.insert(Hashing.polynomialHashCode(words.get(i), a), a);
+ }
+
+ int totalColisions=0, maxColisions=0, currentColisions=0;
+
+ //used to detect 'boundries' between groups of hash codes.
+ int prevHash=hashes.removeMin().getKey();
+ while(!hashes.isEmpty()){
+ //if its the same as the previous, it is p collision.
+ int currentHash=hashes.removeMin().getKey();
+ if(currentHash==prevHash){
+ currentColisions++;
+ totalColisions++;
+ }
+ //we have reached the end of that 'block', store our max collisions (if applicable), and reset current colisions.
+ else{
+ maxColisions=Math.max(maxColisions, currentColisions);
+ currentColisions=0;
+ prevHash=currentHash;
+ }
+ }
+
+ //write the table for value of a
+ hashData[a-30][0]=String.format("%,d", a);
+ hashData[a-30][1]=String.format("%,d", maxColisions);
+ hashData[a-30][2]=String.format("%,d", totalColisions);
+ }
+ String[] colHeaders={"a", "max collisions", "total collisions"};
+ System.out.println(ASCIITable.render(hashData, 2, "Polynomial hash code", colHeaders));
+
+ //lets have p be 92000. (for appropriate load factor). first prime number after is 92003
+ String[][] compressionData = new String[10][3];
+ for(int p=91998; p<92008; p++){
+ //tried using this using an array of buckets, it got... messy
+ HeapPriorityQueue compressions = new HeapPriorityQueue<>();
+ for(int i=0; i< words.size(); i++){
+ //the value doesnt matter
+ compressions.insert(Hashing.madCompression(Hashing.polynomialHashCode(words.get(i), 33), 92000, p, 6578, 75245), p);
+ }
+
+ int totalColisions=0, maxColisions=0, currentColisions=0;
+
+ //used to detect 'boundries' between groups of hash codes.
+ int prevCompression=compressions.removeMin().getKey();
+ while(!compressions.isEmpty()){
+ //if its the same as the previous, it is p collision.
+ int currentCompression=compressions.removeMin().getKey();
+ if(currentCompression==prevCompression){
+ currentColisions++;
+ totalColisions++;
+ }
+ //we have reached the end of that 'block', store our max collisions (if applicable), and reset current colisions.
+ else{
+ maxColisions=Math.max(maxColisions, currentColisions);
+ currentColisions=0;
+ prevCompression=currentCompression;
+ }
+ }
+
+ //write the table for value of p
+ compressionData[p-91998][0]=String.format("%,d", p);
+ compressionData[p-91998][1]=String.format("%,d", maxColisions);
+ compressionData[p-91998][2]=String.format("%,d", totalColisions);
+ }
+
+ String[] colHeaders2={"p", "max collisions", "total collisions"};
+ System.out.println(ASCIITable.render(compressionData, 2, "MAD compression", colHeaders2));
+ }
+}
diff --git a/Lab109/src/DefaultComparator.java b/Lab109/src/DefaultComparator.java
new file mode 100644
index 0000000..d568160
--- /dev/null
+++ b/Lab109/src/DefaultComparator.java
@@ -0,0 +1,20 @@
+
+import java.util.Comparator;
+
+/*
+ * Data Structures & Algorithms 6th Edition
+ * Goodrich, Tamassia, Goldwasser
+ * Code Fragments 9.4
+ *
+ * An implementation of the DefaultComparator class
+ * */
+
+/**
+ *
+ * @author Gabriel Venberg
+ */
+public class DefaultComparator implements Comparator {
+ public int compare(E a, E b) throws ClassCastException{
+ return((Comparable)a).compareTo(b);
+ }
+}
diff --git a/Lab109/src/Entry.java b/Lab109/src/Entry.java
new file mode 100644
index 0000000..a4f7d13
--- /dev/null
+++ b/Lab109/src/Entry.java
@@ -0,0 +1,16 @@
+/*
+ * Data Structures & Algorithms 6th Edition
+ * Goodrich, Tamassia, Goldwasser
+ * Code Fragments 9.1
+ *
+ * An implementation of the Entry Interface
+ * */
+
+/**
+ *
+ * @author Gabriel Venberg
+ */
+public interface Entry {
+ K getKey();
+ V getValue();
+}
diff --git a/Lab109/src/Hashing.java b/Lab109/src/Hashing.java
new file mode 100644
index 0000000..1de81ae
--- /dev/null
+++ b/Lab109/src/Hashing.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 Gabriel Venberg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * an implementation of polynomial hash code and MAD compression functions
+ * @author Gabriel Venberg
+ */
+public class Hashing {
+
+ /**
+ * hashes a given string (x0,x1,...,xn-1) by x0a^n-1+x1a^n-2+...+xn-2a+xn-1. using a given value of a
+ * @param value the string to hash
+ * @param a the value of a to use
+ * @return an int representing the resulting hash.
+ */
+ public static int polynomialHashCode(String value, int a){
+ //due to twos compliment math, we dont actually need to use longs to detect rollover, and can just use a mask to ignore the sign bit!
+ //also, wasted 2 hours because I had set this to MIN_VALUE....
+ final int mask = Integer.MAX_VALUE;
+ int hash=0;
+ //using horners rule iteratively
+ for(int i=0; ib||b>p-1){throw new IllegalArgumentException("b needs to be between 0 and p-1, inclusive.");}
+ if(0>=a||a>p-1){throw new IllegalArgumentException("a needs to be betwwen 1 and p-1, inclusive.");}
+ return ((a*value+b)%p)%N;
+ }
+}
diff --git a/Lab109/src/HeapPriorityQueue.java b/Lab109/src/HeapPriorityQueue.java
new file mode 100644
index 0000000..fbd96d1
--- /dev/null
+++ b/Lab109/src/HeapPriorityQueue.java
@@ -0,0 +1,101 @@
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+/*
+ * Data Structures & Algorithms 6th Edition
+ * Goodrich, Tamassia, Goldwasser
+ * Code Fragments 9.8-9.9
+ *
+ * An implementation of the heapPriortyQueue class
+ * */
+
+/**
+ *
+ * @author Gabriel Venberg
+ */
+public class HeapPriorityQueue extends AbstractPriorityQueue {
+ /** primary collection of priorty queue entries*/
+ protected ArrayList> heap = new ArrayList<>();
+ /**creates an empty priority queue based on the natrual ordering of its keys*/
+ public HeapPriorityQueue(){super();}
+ /** creates an empty priorty queue using the given comparator to order keys.*/
+ public HeapPriorityQueue(Comparator comp){super(comp);}
+ //protected utilities
+ protected int parent(int j){return(j-1)/2;}
+ protected int left(int j){return 2*j+1;}
+ protected int right(int j){return 2*j+2;}
+ protected boolean hasLeft(int j){return left(j) temp = heap.get(i);
+ heap.set(i, heap.get(j));
+ heap.set(j, temp);
+ }
+
+ /** moves the entry at index j higher, if necessary, to restore heap property*/
+ protected void upheap(int j){
+ //continue till reaching root or break statemetnt
+ while(j>0){
+ int p=parent(j);
+ //heap verified
+ if(compare(heap.get(j), heap.get(p))>=0){break;}
+ swap(j,p);
+ //continue from the parents location.
+ j=p;
+ }
+ }
+
+ /** moves the entry at index j lower, if necessayr, to restore the heap property */
+ protected void downheap(int j){
+ while(hasLeft(j)) { //continue to bottom or break statement.
+ int leftIndex=left(j);
+ //although right may be smaller
+ int smallChildIndex = leftIndex;
+ if(hasRight(j)){
+ int rightIndex=right(j);
+ if(compare(heap.get(leftIndex), heap.get(rightIndex))>0){
+ smallChildIndex=rightIndex;
+ }
+ }
+ if(compare(heap.get(smallChildIndex), heap.get(j))>=0){break;}
+ swap(j, smallChildIndex);
+ j=smallChildIndex;
+ }
+ }
+
+ //public methods
+ /**returns the number of items in the priority queue*/
+ public int size(){return heap.size();}
+
+ /**returns but does not remove an entry with minimal key (if any)*/
+ public Entry min(){
+ if(heap.isEmpty()){return null;}
+ return heap.get(0);
+ }
+
+ /**inserts a key value pair and returns the entry created*/
+ public Entry insert(K key, V value) throws IllegalArgumentException{
+ checkKey(key); //could throw exceptions.
+ Entry newest = new PQEntry<>(key,value);
+ //add to end of the list
+ heap.add(newest);
+ //and upheap
+ upheap(heap.size()-1);
+ return newest;
+ }
+
+ /**removes and returns an entry with minimal key(if any)*/
+ public Entry removeMin(){
+ if(heap.isEmpty()){return null;}
+ Entry answer = heap.get(0);
+ //put minimum item at the end
+ swap(0, heap.size()-1);
+ //and remove from list
+ heap.remove(heap.size()-1);
+ //then fix the new root.
+ downheap(0);
+ return answer;
+ }
+}
diff --git a/Lab109/src/PriorityQueue.java b/Lab109/src/PriorityQueue.java
new file mode 100644
index 0000000..ed45ff2
--- /dev/null
+++ b/Lab109/src/PriorityQueue.java
@@ -0,0 +1,19 @@
+/*
+ * Data Structures & Algorithms 6th Edition
+ * Goodrich, Tamassia, Goldwasser
+ * Code Fragments 9.2
+ *
+ * An implementation of the PriorityQueue interface
+ * */
+
+/**
+ *
+ * @author Gabriel Venberg
+ */
+public interface PriorityQueue {
+ int size();
+ boolean isEmpty();
+ Entry insert(K key, V value) throws IllegalArgumentException;
+ Entry min();
+ Entry removeMin();
+}