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(); +}