Lab109
This commit is contained in:
parent
b1fe8d6ea1
commit
29c576c988
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -46,3 +46,4 @@ hs_err_pid*
|
||||||
/Lab108-VenbergGE/nbproject/private/
|
/Lab108-VenbergGE/nbproject/private/
|
||||||
/Lab108-VenbergGE/build/
|
/Lab108-VenbergGE/build/
|
||||||
/Lab108-VenbergGE/dist/
|
/Lab108-VenbergGE/dist/
|
||||||
|
/Lab109/build/
|
||||||
|
|
181
Lab109/src/ASCIITable.java
Normal file
181
Lab109/src/ASCIITable.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<data.length; i++){
|
||||||
|
string = string+horizontalSpacer+"\n";
|
||||||
|
string = string+dataString(colWidths, padding, data[i])+'\n';
|
||||||
|
}
|
||||||
|
string = string+horizontalSpacer;
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String tableHeader(String header, int width){
|
||||||
|
String string="|";
|
||||||
|
int halfPadding=(width-header.length())/2;
|
||||||
|
//front padding
|
||||||
|
for(int i=0; i<halfPadding; i++){string=string+" ";}
|
||||||
|
//if the total padding we need is odd, put it in front of the header
|
||||||
|
if((width-header.length())%2==1){string=string+" ";}
|
||||||
|
string=string+header;
|
||||||
|
//rear padding
|
||||||
|
for(int i=0; i<halfPadding; i++){string=string+" ";}
|
||||||
|
string=string+"|";
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calcs the sum of all elements in an int array
|
||||||
|
* @param array array to be summed
|
||||||
|
* @return sum of array
|
||||||
|
*/
|
||||||
|
private static int sumOfArray(int[] array){
|
||||||
|
int sum=0;
|
||||||
|
for(int i=0; i<array.length; i++){
|
||||||
|
sum += array[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates the maximum number of entries the rows in the data set have
|
||||||
|
* @param data 2D array of data
|
||||||
|
* @return needed number of rows in the final table.
|
||||||
|
*/
|
||||||
|
private static int calcNoCols(Object data[][]){
|
||||||
|
int rows = 0;
|
||||||
|
for(int i=0; i<data.length; i++){
|
||||||
|
rows = Math.max(rows, data[i].length);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates the needed column widths for a data array without padding
|
||||||
|
* @param data the array of data
|
||||||
|
* @return an array of integers representing the needed width of each column
|
||||||
|
*/
|
||||||
|
private static int[] calcColumnWidth(int cols, Object data[][], String[] headers){
|
||||||
|
int[] maxWidths = new int[cols];
|
||||||
|
for(int i=0; i<cols; i++){
|
||||||
|
maxWidths[i]=headers[i].length();
|
||||||
|
for(int j=0; j<data.length; j++){
|
||||||
|
maxWidths[i]=Math.max(maxWidths[i], data[j][i].toString().length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxWidths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gives the horizontal spacer needed for the table
|
||||||
|
* @param colWidth width of each column;
|
||||||
|
* @param padding padding on each side of data.
|
||||||
|
* @param noOfCols number of columns;
|
||||||
|
* @return a string suitable to use as the horizontal spacer for the table.
|
||||||
|
*/
|
||||||
|
private static String assembleHorizontalSpacers(int[] colWidth, int padding, int noOfCols){
|
||||||
|
String string = "+";
|
||||||
|
for(int i=0; i<noOfCols; i++){
|
||||||
|
for(int j=0; j<colWidth[i]+2*padding; j++){
|
||||||
|
string = string+'-';
|
||||||
|
}
|
||||||
|
string = string+'+';
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* takes a single row of the data array and returns a row. Make sure your colWidth is accurate.
|
||||||
|
* @param colWidth width of each column
|
||||||
|
* @param padding min padding to have around each entry
|
||||||
|
* @param data 1D array of data to print
|
||||||
|
* @return a string containing the data
|
||||||
|
*/
|
||||||
|
private static String dataString(int[] colWidth, int padding, Object data[]){
|
||||||
|
String string ="|";
|
||||||
|
//for each entry in the row
|
||||||
|
for(int i=0; i<data.length; i++){
|
||||||
|
//only calc this once.
|
||||||
|
int length=data[i].toString().length();
|
||||||
|
// front padding. Also, I wish java had string multiplication.
|
||||||
|
for(int p=0; p<padding+(colWidth[i]-length); p++){string = string+" ";}
|
||||||
|
string = string+data[i].toString();
|
||||||
|
//rear padding
|
||||||
|
for(int p=0; p<padding; p++){string = string+" ";}
|
||||||
|
string = string+"|";
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* takes an array of strings (column headers) and outputs a single row of the column, center justified.
|
||||||
|
* @param colWidth width of each column
|
||||||
|
* @param padding min padding around each entry
|
||||||
|
* @param columnHeaders 1d array of strings containing col headers
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String columnHeaderString(int[] colWidth, int padding, String columnHeaders[]){
|
||||||
|
String string="|";
|
||||||
|
for(int i=0; i<columnHeaders.length; i++){
|
||||||
|
//calc this once.
|
||||||
|
int length=columnHeaders[i].length();
|
||||||
|
int sidePadding=(colWidth[i]-length+padding*2)/2;
|
||||||
|
//front padding
|
||||||
|
for(int p=0; p<sidePadding; p++){string=string+" ";}
|
||||||
|
//if we need an odd number of total padding, add the spare on the front
|
||||||
|
if((colWidth[i]-length)%2==1){string=string+" ";}
|
||||||
|
string=string+columnHeaders[i];
|
||||||
|
//rear padding
|
||||||
|
for(int p=0; p<sidePadding; p++){string=string+" ";}
|
||||||
|
string=string+"|";
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
60
Lab109/src/AbstractPriorityQueue.java
Normal file
60
Lab109/src/AbstractPriorityQueue.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data Structures & Algorithms 6th Edition
|
||||||
|
* Goodrich, Tamassia, Goldwasser
|
||||||
|
* Code Fragments 9.6
|
||||||
|
*
|
||||||
|
* An implementation of the AbstractPriorityQueue class
|
||||||
|
* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Gabriel Venberg
|
||||||
|
*/
|
||||||
|
public abstract class AbstractPriorityQueue<K,V> implements PriorityQueue<K,V> {
|
||||||
|
|
||||||
|
//nested PQEntry class
|
||||||
|
protected static class PQEntry<K,V> implements Entry<K,V> {
|
||||||
|
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<K> comp;
|
||||||
|
|
||||||
|
/** Creates an empty priority queue using the given comparator to order keys. */
|
||||||
|
protected AbstractPriorityQueue(Comparator<K> c){comp=c;}
|
||||||
|
|
||||||
|
/** creates an empty priority queue based on the natrual ordering of its keys */
|
||||||
|
protected AbstractPriorityQueue(){this(new DefaultComparator<K>());}
|
||||||
|
|
||||||
|
/** method for comparing two entries according to the key*/
|
||||||
|
protected int compare(Entry<K,V> a, Entry<K,V> 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;}
|
||||||
|
}
|
122
Lab109/src/Client.java
Normal file
122
Lab109/src/Client.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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<String> 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<Integer,Integer> 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<Integer,Integer> 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));
|
||||||
|
}
|
||||||
|
}
|
20
Lab109/src/DefaultComparator.java
Normal file
20
Lab109/src/DefaultComparator.java
Normal file
|
@ -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<E> implements Comparator<E> {
|
||||||
|
public int compare(E a, E b) throws ClassCastException{
|
||||||
|
return((Comparable<E>)a).compareTo(b);
|
||||||
|
}
|
||||||
|
}
|
16
Lab109/src/Entry.java
Normal file
16
Lab109/src/Entry.java
Normal file
|
@ -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,V>{
|
||||||
|
K getKey();
|
||||||
|
V getValue();
|
||||||
|
}
|
57
Lab109/src/Hashing.java
Normal file
57
Lab109/src/Hashing.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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; i<value.length(); i++){
|
||||||
|
hash = (hash * a) + (int) value.charAt(i);
|
||||||
|
}
|
||||||
|
// im *pretty sure* we only need to zero the sign bit once... will test
|
||||||
|
return hash&mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compresses a hash code with by multiply add divide method with given constants
|
||||||
|
* @param value the hash code to compress
|
||||||
|
* @param N the given value of N (should be the size of your bucket array if using to make hash table)
|
||||||
|
* @param p should be a prime number larger than N
|
||||||
|
* @param a random value between 1 and p-1
|
||||||
|
* @param b random value between 0 and p-1
|
||||||
|
* @return the compressed hash.
|
||||||
|
*/
|
||||||
|
public static int madCompression(int value, int N, int p, int a, int b) throws IllegalArgumentException{
|
||||||
|
if(0>b||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;
|
||||||
|
}
|
||||||
|
}
|
101
Lab109/src/HeapPriorityQueue.java
Normal file
101
Lab109/src/HeapPriorityQueue.java
Normal file
|
@ -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<K,V> extends AbstractPriorityQueue<K,V> {
|
||||||
|
/** primary collection of priorty queue entries*/
|
||||||
|
protected ArrayList<Entry<K,V>> 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<K> 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)<heap.size();}
|
||||||
|
protected boolean hasRight(int j){return right(j)<heap.size();}
|
||||||
|
|
||||||
|
protected void swap(int i, int j){
|
||||||
|
Entry<K,V> 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<K,V> min(){
|
||||||
|
if(heap.isEmpty()){return null;}
|
||||||
|
return heap.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**inserts a key value pair and returns the entry created*/
|
||||||
|
public Entry<K,V> insert(K key, V value) throws IllegalArgumentException{
|
||||||
|
checkKey(key); //could throw exceptions.
|
||||||
|
Entry<K,V> 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<K,V> removeMin(){
|
||||||
|
if(heap.isEmpty()){return null;}
|
||||||
|
Entry<K,V> 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;
|
||||||
|
}
|
||||||
|
}
|
19
Lab109/src/PriorityQueue.java
Normal file
19
Lab109/src/PriorityQueue.java
Normal file
|
@ -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 <K,V> {
|
||||||
|
int size();
|
||||||
|
boolean isEmpty();
|
||||||
|
Entry<K,V> insert(K key, V value) throws IllegalArgumentException;
|
||||||
|
Entry<K,V> min();
|
||||||
|
Entry<K,V> removeMin();
|
||||||
|
}
|
Reference in a new issue