Skip to content

Commit ca08206

Browse files
committed
More improvements in the probing hashmap performance
1 parent 45f1c90 commit ca08206

File tree

1 file changed

+53
-51
lines changed

1 file changed

+53
-51
lines changed

src/com/jwetherell/algorithms/data_structures/HashMap.java

+53-51
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,14 @@ private void reduce() {
187187
* Increases the input ten-fold
188188
*/
189189
private static final int getLargerSize(int input) {
190-
return input*10;
190+
return input<<1;
191191
}
192192

193193
/**
194194
* Reduces the input to a fourth
195195
*/
196196
private static final int getSmallerSize(int input) {
197-
return input/4;
197+
return input>>1>>1;
198198
}
199199

200200
/**
@@ -339,16 +339,17 @@ public java.util.Iterator<java.util.Map.Entry<K, V>> iterator() {
339339

340340
private static class ProbingHashMap<K, V> extends HashMap<K, V> {
341341

342-
private float loadFactor = 0.75f;
342+
private int hashingKey = -1;
343+
private float loadFactor = 0.6f;
343344
private int minimumSize = 1024;
344345
private Pair<K, V>[] array = null;
345346
private int size = 0;
346347

347348
/**
348-
* Create a hash map with K as the hashing key.
349+
* Create a hash map with K as the hash.
349350
*
350351
* @param size
351-
* initial size.
352+
* to use for the hash.
352353
*/
353354
public ProbingHashMap(int size) {
354355
initializeMap(size);
@@ -371,30 +372,31 @@ public V put(K key, V value) {
371372

372373
private V put(Pair<K,V> newPair) {
373374
V prev = null;
374-
int index = indexOf(newPair.key.hashCode(), array.length);
375+
int hashedKey = hashingFunction(newPair.key);
375376

376377
// Check initial position
377-
Pair<K, V> pair = array[index];
378+
Pair<K, V> pair = array[hashedKey];
378379
if (pair == null) {
379-
array[index] = newPair;
380+
array[hashedKey] = newPair;
380381
size++;
381382

382383
// If size is greater than threshold
383384
int maxSize = (int)(loadFactor*array.length);
384385
if (size >= maxSize)
385-
resize();
386+
increase();
386387

387388
return prev;
388389
}
390+
389391
if (pair.key.equals(newPair.key)) {
390392
prev = pair.value;
391393
pair.value = newPair.value;
392394
return prev;
393395
}
394396

395397
// Probing until we get back to the starting index
396-
int start = getNextIndex(index);
397-
while (start != index) {
398+
int start = getNextIndex(hashedKey);
399+
while (start != hashedKey) {
398400
pair = array[start];
399401
if (pair == null) {
400402
array[start] = newPair;
@@ -403,10 +405,11 @@ private V put(Pair<K,V> newPair) {
403405
// If size is greater than threshold
404406
int maxSize = (int)(loadFactor*array.length);
405407
if (size >= maxSize)
406-
resize();
408+
increase();
407409

408410
return prev;
409411
}
412+
410413
if (pair.key.equals(newPair.key)) {
411414
prev = pair.value;
412415
pair.value = newPair.value;
@@ -424,18 +427,20 @@ private V put(Pair<K,V> newPair) {
424427
*/
425428
@Override
426429
public V get(K key) {
430+
int hashedKey = hashingFunction(key);
431+
Pair<K, V> pair = array[hashedKey];
432+
427433
// Check initial position
428-
int index = indexOf(key.hashCode(), array.length);
429-
Pair<K, V> pair = array[index];
430434
if (pair == null)
431435
return null;
432436
if (pair.key.equals(key))
433437
return pair.value;
434438

435439
// Probing until we get back to the starting index
436-
int start = getNextIndex(index);
437-
while (start != index) {
440+
int start = getNextIndex(hashedKey);
441+
while (start != hashedKey) {
438442
pair = array[start];
443+
439444
if (pair == null)
440445
return null;
441446
if (pair.key.equals(key))
@@ -460,13 +465,14 @@ public boolean contains(K key) {
460465
*/
461466
@Override
462467
public V remove(K key) {
463-
// Check initial position
464-
int index = indexOf(key.hashCode(), array.length);
468+
int hashedKey = hashingFunction(key);
465469
Pair<K, V> prev = null;
466-
Pair<K, V> pair = array[index];
467-
if (pair!=null && pair.key.equals(key)) {
468-
prev = array[index];
469-
array[index] = null;
470+
471+
// Check initial position
472+
Pair<K, V> pair = array[hashedKey];
473+
if (pair != null && pair.key.equals(key)) {
474+
prev = array[hashedKey];
475+
array[hashedKey] = null;
470476
size--;
471477

472478
int loadFactored = (int)(size/loadFactor);
@@ -478,10 +484,10 @@ public V remove(K key) {
478484
}
479485

480486
// Probing until we get back to the starting index
481-
int start = getNextIndex(index);
482-
while (start != index) {
487+
int start = getNextIndex(hashedKey);
488+
while (start != hashedKey) {
483489
pair = array[start];
484-
if (pair!=null && pair.key.equals(key)) {
490+
if (pair != null && pair.key.equals(key)) {
485491
prev = array[start];
486492
array[start] = null;
487493
size--;
@@ -493,7 +499,6 @@ public V remove(K key) {
493499

494500
return prev.value;
495501
}
496-
497502
start = getNextIndex(start);
498503
}
499504
// If we get here, probing failed.
@@ -518,13 +523,20 @@ public int size() {
518523
return size;
519524
}
520525

521-
private void resize() {
526+
private void initializeMap(int current) {
527+
int length = getLargerSize(current);
528+
array = new Pair[length];
529+
size = 0;
530+
hashingKey = length;
531+
}
532+
533+
private void increase() {
522534
// Save old data
523535
Pair<K,V>[] temp = this.array;
524536

525537
// Calculate new size and assign
526538
int length = getLargerSize(array.length);
527-
//System.out.println("resize from "+array.length+" to "+length);
539+
//System.out.println("increase from "+array.length+" to "+length);
528540
initializeMap(length);
529541

530542
// Re-hash old data
@@ -551,51 +563,41 @@ private void reduce() {
551563
}
552564

553565
/**
554-
* Returns the closest base 2 number (2^x) which is larger than the 2*input
566+
* Returns double of the input
555567
*/
556568
private static final int getLargerSize(int input) {
557-
int b = (int)((Math.log(2*input) / Math.log(2)));
558-
int length = (int) Math.pow(2, b);
559-
return length;
569+
return input<<1;
560570
}
561571

562572
/**
563-
* Returns the closest base 2 number (2^x) which is smaller than the input/3
573+
* Returns one fourth of the input
564574
*/
565575
private static final int getSmallerSize(int input) {
566-
int b = (int)((Math.log(input/3) / Math.log(2)));
567-
int length = (int) Math.pow(2, b);
568-
return length;
569-
}
570-
571-
/**
572-
* Initialize the hash array.
573-
*/
574-
private void initializeMap(int length) {
575-
this.array = new Pair[length];
576-
this.size = 0;
576+
return input>>1>>1;
577577
}
578578

579579
/**
580580
* Returns the next index in the probing sequence, at this point it's linear
581581
*/
582-
private int getNextIndex(int idx) {
583-
// Linear probing
584-
int i = idx+1;
582+
private int getNextIndex(int input) {
583+
int i = input+1;
585584
if (i >= array.length)
586-
i %= array.length;
585+
i = 0;
587586
return i;
588587
}
589588

590589
/**
591590
* The hashing function. Converts the key into an integer.
592591
*
593-
* @param h
592+
* @param key
594593
* to create a hash for.
595594
* @return Integer which represents the key.
596595
*/
597-
private int indexOf(int h, int length) {
598-
return h & (length-1);
596+
private int hashingFunction(K key) {
597+
int k = key.hashCode() % hashingKey;
598+
if (k>=array.length)
599+
k = k - ((k/array.length) * array.length);
600+
return k;
599601
}
600602

601603
/**

0 commit comments

Comments
 (0)