diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java index c96da27c0331..10d5dc7decae 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java @@ -2,24 +2,51 @@ import java.util.ArrayList; -/*** - * This class is an implementation of a hash table using linear probing. +/** + * This class implements a hash table using linear probing to resolve collisions. + * Linear probing is a collision resolution method where each slot in the hash table is checked in a sequential manner + * until an empty slot is found. + * + *

+ * The class allows for storing key-value pairs, where both the key and value are generic types. + * The key must be of a type that implements the Comparable interface to ensure that the keys can be compared for sorting. + *

+ * + *

+ * This implementation supports basic operations such as: + *

+ *

+ * + *

+ * The internal size of the hash table is automatically resized when the load factor exceeds 0.5 or falls below 0.125, + * ensuring efficient space utilization. + *

+ * * @see Linear Probing Hash Table * - * @param keys type. - * @param values type. + * @param the type of keys maintained by this map + * @param the type of mapped values */ public class LinearProbingHashMap, Value> extends Map { private int hsize; // size of the hash table - private Key[] keys; - private Value[] values; - private int size; // amount of elements in the hash table + private Key[] keys; // array to store keys + private Value[] values; // array to store values + private int size; // number of elements in the hash table + // Default constructor initializes the table with a default size of 16 public LinearProbingHashMap() { this(16); } @SuppressWarnings("unchecked") + // Constructor to initialize the hash table with a specified size public LinearProbingHashMap(int size) { this.hsize = size; keys = (Key[]) new Comparable[size]; @@ -81,7 +108,7 @@ public boolean delete(Key key) { i = increment(i); while (keys[i] != null) { - // delete keys[i] an vals[i] and reinsert + // Save the key and value for rehashing Key keyToRehash = keys[i]; Value valToRehash = values[i]; keys[i] = null; diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java index d0a72a1509ee..34b165d4bbcf 100644 --- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java +++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java @@ -1,8 +1,91 @@ package com.thealgorithms.datastructures.hashmap.hashing; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + class LinearProbingHashMapTest extends MapTest { + @Override , Value> Map getMap() { return new LinearProbingHashMap<>(); } + + @Test + void putNullKey() { + Map map = getMap(); + assertFalse(map.put(null, "value"), "Putting a null key should return false"); + } + + @Test + void putDuplicateKeys() { + Map map = getMap(); + map.put(1, "one"); + map.put(1, "uno"); + assertEquals("uno", map.get(1), "Value should be updated to 'uno'"); + } + + @Test + void putResizeTest() { + Map map = getMap(); + for (int i = 0; i < 20; i++) { + map.put(i, String.valueOf(i)); + } + assertEquals(20, map.size(), "Map size should be 20 after inserting 20 elements"); + } + + @Test + void deleteNonExistentKey() { + Map map = getMap(); + assertFalse(map.delete(999), "Deleting a non-existent key should return false"); + } + + @Test + void deleteAndReinsert() { + Map map = getMap(); + map.put(1, "one"); + map.delete(1); + assertFalse(map.contains(1), "Map should not contain the deleted key"); + map.put(1, "one again"); + assertTrue(map.contains(1), "Map should contain the key after reinsertion"); + } + + @Test + void resizeDown() { + Map map = getMap(); + for (int i = 0; i < 16; i++) { + map.put(i, String.valueOf(i)); + } + for (int i = 0; i < 12; i++) { + map.delete(i); + } + assertEquals(4, map.size(), "Map size should be 4 after deleting 12 elements"); + } + + @Test + void keysOrderTest() { + Map map = getMap(); + for (int i = 10; i > 0; i--) { + map.put(i, String.valueOf(i)); + } + int expectedKey = 1; + for (Integer key : map.keys()) { + assertEquals(expectedKey++, key, "Keys should be in sorted order"); + } + } + + @Test + void stressTest() { + Map map = getMap(); + for (int i = 0; i < 1000; i++) { + map.put(i, String.valueOf(i)); + assertEquals(i + 1, map.size(), "Size should match number of inserted elements"); + } + for (int i = 0; i < 500; i++) { + map.delete(i); + assertEquals(1000 - (i + 1), map.size(), "Size should decrease correctly"); + } + } }