Skip to content

Commit 26f114c

Browse files
authored
Enhance docs, add tests in LinearProbingHashMap (#5977)
1 parent 4ea3098 commit 26f114c

File tree

2 files changed

+118
-8
lines changed

2 files changed

+118
-8
lines changed

src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,51 @@
22

33
import java.util.ArrayList;
44

5-
/***
6-
* This class is an implementation of a hash table using linear probing.
5+
/**
6+
* This class implements a hash table using linear probing to resolve collisions.
7+
* Linear probing is a collision resolution method where each slot in the hash table is checked in a sequential manner
8+
* until an empty slot is found.
9+
*
10+
* <p>
11+
* The class allows for storing key-value pairs, where both the key and value are generic types.
12+
* The key must be of a type that implements the Comparable interface to ensure that the keys can be compared for sorting.
13+
* </p>
14+
*
15+
* <p>
16+
* This implementation supports basic operations such as:
17+
* <ul>
18+
* <li><b>put(Key key, Value value)</b>: Adds a key-value pair to the hash table. If the key already exists, its value is updated.</li>
19+
* <li><b>get(Key key)</b>: Retrieves the value associated with the given key.</li>
20+
* <li><b>delete(Key key)</b>: Removes the key and its associated value from the hash table.</li>
21+
* <li><b>contains(Key key)</b>: Checks if the hash table contains a given key.</li>
22+
* <li><b>size()</b>: Returns the number of key-value pairs in the hash table.</li>
23+
* <li><b>keys()</b>: Returns an iterable collection of keys stored in the hash table.</li>
24+
* </ul>
25+
* </p>
26+
*
27+
* <p>
28+
* The internal size of the hash table is automatically resized when the load factor exceeds 0.5 or falls below 0.125,
29+
* ensuring efficient space utilization.
30+
* </p>
31+
*
732
* @see <a href="https://en.wikipedia.org/wiki/Linear_probing">Linear Probing Hash Table</a>
833
*
9-
* @param <Key> keys type.
10-
* @param <Value> values type.
34+
* @param <Key> the type of keys maintained by this map
35+
* @param <Value> the type of mapped values
1136
*/
1237
public class LinearProbingHashMap<Key extends Comparable<Key>, Value> extends Map<Key, Value> {
1338
private int hsize; // size of the hash table
14-
private Key[] keys;
15-
private Value[] values;
16-
private int size; // amount of elements in the hash table
39+
private Key[] keys; // array to store keys
40+
private Value[] values; // array to store values
41+
private int size; // number of elements in the hash table
1742

43+
// Default constructor initializes the table with a default size of 16
1844
public LinearProbingHashMap() {
1945
this(16);
2046
}
2147

2248
@SuppressWarnings("unchecked")
49+
// Constructor to initialize the hash table with a specified size
2350
public LinearProbingHashMap(int size) {
2451
this.hsize = size;
2552
keys = (Key[]) new Comparable[size];
@@ -81,7 +108,7 @@ public boolean delete(Key key) {
81108

82109
i = increment(i);
83110
while (keys[i] != null) {
84-
// delete keys[i] an vals[i] and reinsert
111+
// Save the key and value for rehashing
85112
Key keyToRehash = keys[i];
86113
Value valToRehash = values[i];
87114
keys[i] = null;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,91 @@
11
package com.thealgorithms.datastructures.hashmap.hashing;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import org.junit.jupiter.api.Test;
8+
39
class LinearProbingHashMapTest extends MapTest {
10+
411
@Override
512
<Key extends Comparable<Key>, Value> Map<Key, Value> getMap() {
613
return new LinearProbingHashMap<>();
714
}
15+
16+
@Test
17+
void putNullKey() {
18+
Map<Integer, String> map = getMap();
19+
assertFalse(map.put(null, "value"), "Putting a null key should return false");
20+
}
21+
22+
@Test
23+
void putDuplicateKeys() {
24+
Map<Integer, String> map = getMap();
25+
map.put(1, "one");
26+
map.put(1, "uno");
27+
assertEquals("uno", map.get(1), "Value should be updated to 'uno'");
28+
}
29+
30+
@Test
31+
void putResizeTest() {
32+
Map<Integer, String> map = getMap();
33+
for (int i = 0; i < 20; i++) {
34+
map.put(i, String.valueOf(i));
35+
}
36+
assertEquals(20, map.size(), "Map size should be 20 after inserting 20 elements");
37+
}
38+
39+
@Test
40+
void deleteNonExistentKey() {
41+
Map<Integer, String> map = getMap();
42+
assertFalse(map.delete(999), "Deleting a non-existent key should return false");
43+
}
44+
45+
@Test
46+
void deleteAndReinsert() {
47+
Map<Integer, String> map = getMap();
48+
map.put(1, "one");
49+
map.delete(1);
50+
assertFalse(map.contains(1), "Map should not contain the deleted key");
51+
map.put(1, "one again");
52+
assertTrue(map.contains(1), "Map should contain the key after reinsertion");
53+
}
54+
55+
@Test
56+
void resizeDown() {
57+
Map<Integer, String> map = getMap();
58+
for (int i = 0; i < 16; i++) {
59+
map.put(i, String.valueOf(i));
60+
}
61+
for (int i = 0; i < 12; i++) {
62+
map.delete(i);
63+
}
64+
assertEquals(4, map.size(), "Map size should be 4 after deleting 12 elements");
65+
}
66+
67+
@Test
68+
void keysOrderTest() {
69+
Map<Integer, String> map = getMap();
70+
for (int i = 10; i > 0; i--) {
71+
map.put(i, String.valueOf(i));
72+
}
73+
int expectedKey = 1;
74+
for (Integer key : map.keys()) {
75+
assertEquals(expectedKey++, key, "Keys should be in sorted order");
76+
}
77+
}
78+
79+
@Test
80+
void stressTest() {
81+
Map<Integer, String> map = getMap();
82+
for (int i = 0; i < 1000; i++) {
83+
map.put(i, String.valueOf(i));
84+
assertEquals(i + 1, map.size(), "Size should match number of inserted elements");
85+
}
86+
for (int i = 0; i < 500; i++) {
87+
map.delete(i);
88+
assertEquals(1000 - (i + 1), map.size(), "Size should decrease correctly");
89+
}
90+
}
891
}

0 commit comments

Comments
 (0)