1/*2 * OpenHashTable.java3 *4 * Computer Science S-22, Harvard University5 */6 7/*8 * A class that implements a hash table that employs open addressing9 * using either linear probing, quadratic probing, or double hashing.10 */11public class OpenHashTable implements HashTable {12 /* Private inner class for an entry in the hash table */13 private class Entry {14 private Object key;15 private LLQueue<Object> values; // all of the values with this key16 17 private Entry(Object key, Object value) {18 this.key = key;19 values = new LLQueue<Object>();20 values.insert(value);21 }22 }23 24 // possible types of probing25 public static final int LINEAR = 0;26 public static final int QUADRATIC = 1;27 public static final int DOUBLE_HASHING = 2;28 public static final int NUM_PROBE_TYPES = 3;29 30 private Entry[] table; // the hash table itself31 private int probeType = LINEAR; // the type of probing32 33 public OpenHashTable(int size, int probeType) {34 if (size <= 0) {35 throw new IllegalArgumentException("size must be positive");36 }37 if (probeType < 0 || probeType >= NUM_PROBE_TYPES) {38 throw new IllegalArgumentException("invalid probeType: " + probeType);39 }40 41 table = new Entry[size];42 this.probeType = probeType;43 }44 45 /*46 * Constructor for a hash table of the specified size that uses double hashing47 */ 48 public OpenHashTable(int size) {49 // call the other constructor to do the work50 this(size, DOUBLE_HASHING);51 }52 53 /* first hash function */54 public int h1(Object key) {55 int h1 = key.hashCode() % table.length;56 if (h1 < 0) {57 h1 += table.length;58 }59 return h1;60 }61 62 /* second hash function */63 public int h2(Object key) {64 int h2 = key.hashCode() % 5;65 if (h2 < 0) {66 h2 += 11;67 }68 h2 += 5;69 return h2;70 }71 72 /* 73 * probeIncr - returns the amount by which the current index74 * should be incremented to obtain the next element in the probe75 * sequence if we have already checked numChecked positions76 * and h2 is the value of the second hash function77 */78 private int probeIncr(int numChecked, int h2) {79 if (numChecked <= 0) {80 return 0;81 } else if (probeType == LINEAR) {82 return 1;83 } else if (probeType == QUADRATIC) {84 return (2*numChecked - 1);85 } else { // DOUBLE_HASHING:86 return h2;87 }88 }89 90 /*91 * probe - attempt to find a slot in the hash table for the specified key.92 *93 * If key is currently in the table, it returns the index of the entry.94 * If key isn't in the table, it returns the index of the first empty cell95 * in the table.96 * If overflow occurs, it returns -1.97 */98 private int probe(Object key) {99 int i = h1(key); // first hash function100 int h2 = h2(key); // second hash function101 int numChecked = 1;102 103 // keep probing until we get an empty position or a match104 while (table[i] != null && !key.equals(table[i].key)) {105 if (numChecked == table.length) {106 return -1;107 }108 109 i = (i + probeIncr(numChecked, h2)) % table.length;110 numChecked++;111 }112 113 return i;114 }115 116 /*117 * insert - insert the specified (key, value) pair in the hash table.118 * Returns true if the pair can be added and false if there is overflow.119 */120 public boolean insert(Object key, Object value) {121 if (key == null) {122 throw new IllegalArgumentException("key must be non-null");123 }124 125 int i = h1(key); 126 int h2 = h2(key);127 int numChecked = 1;128 int firstRemoved = -1;129 130 while (table[i] != null && !key.equals(table[i].key)) {131 // record the index of the first removed cell we see132 if (table[i].key == null && firstRemoved == -1) {133 firstRemoved = i;134 }135 136 if (numChecked == table.length) {137 break;138 }139 140 i = (i + probeIncr(numChecked, h2)) % table.length;141 numChecked++;142 }143 144 if (table[i] != null && key.equals(table[i].key)) {145 table[i].values.insert(value);146 } else if (firstRemoved != -1) {147 table[firstRemoved] = new Entry(key, value);148 } else if (table[i] == null) {149 table[i] = new Entry(key, value);150 } else {151 return false;152 }153 154 return true;155 }156 157 /*158 * search - search for the specified key and return the159 * associated collection of values, or null if the key 160 * is not in the table161 */162 public Queue<Object> search(Object key) {163 if (key == null) {164 throw new IllegalArgumentException("key must be non-null");165 }166 167 int i = probe(key);168 169 if (i == -1 || table[i] == null) {170 return null;171 } else {172 return table[i].values;173 }174 }175 176 /* 177 * remove - remove from the table the entry for the specified key178 * and return the associated collection of values, or null if the key 179 * is not in the table180 */181 public Queue<Object> remove(Object key) {182 if (key == null) {183 throw new IllegalArgumentException("key must be non-null");184 }185 186 int i = probe(key);187 if (i == -1 || table[i] == null) {188 return null;189 }190 191 LLQueue<Object> removedVals = table[i].values;192 table[i].key = null;193 table[i].values = null;194 return removedVals;195 }196}
int LINEAR
Field defined at line 25.
int QUADRATIC
Field defined at line 26.
int DOUBLE_HASHING
Field defined at line 27.
int NUM_PROBE_TYPES
Field defined at line 28.
Entry[] table
Field defined at line 30.
int probeType
Field defined at line 31.
OpenHashTable(size, probeType)
Constructor defined at line 33.
OpenHashTable(size)
Constructor defined at line 48.
h1(key)
Method defined at line 54.
h2(key)
Method defined at line 63.
probeIncr(numChecked, h2)
Method defined at line 78.
probe(key)
Method defined at line 98.
insert(key, value)
Method defined at line 120.
search(key)
Method defined at line 162.
remove(key)
Method defined at line 181.