Skip to content

Commit dfe1b62

Browse files
author
Lord-of-Algorithms
committed
Add HashTable class and demonstration in Main
1 parent 5a64146 commit dfe1b62

File tree

3 files changed

+315
-0
lines changed

3 files changed

+315
-0
lines changed

src/hashtable/HashFunctionType.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package hashtable;
2+
3+
public enum HashFunctionType {
4+
Division,
5+
Multiplication
6+
}

src/hashtable/HashTable.java

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package hashtable;
2+
3+
/**
4+
* A hash table implementation using chaining with linked lists to resolve collisions.
5+
* This class provides methods for inserting, retrieving, and removing key-value pairs,
6+
* where keys are strings and values are double precision numbers.
7+
*/
8+
public class HashTable {
9+
10+
private HashTableBucket[] bucketArray;
11+
private int size; // Number of key-value pairs in the hash table
12+
private HashFunctionType hashFunctionType;
13+
private static final double A = (Math.sqrt(5) - 1) / 2; // Constant for Multiplication Method
14+
15+
private static final double MAX_LOAD_FACTOR = 0.75;
16+
17+
public HashTable(int capacity, HashFunctionType hashFunctionType) {
18+
if (capacity < 1) {
19+
throw new IllegalArgumentException("Initial capacity must be >= 1");
20+
}
21+
// Adjust capacity to the next prime number if it's not already prime
22+
capacity = isPrime(capacity) ? capacity : nextPrime(capacity);
23+
bucketArray = new HashTableBucket[capacity];
24+
this.hashFunctionType = hashFunctionType;
25+
}
26+
27+
// Computes the hash value for a given key
28+
private int hash(String key) {
29+
int hashCode = key.hashCode();
30+
31+
switch (hashFunctionType) {
32+
case Division:
33+
return Math.abs(hashCode) % bucketArray.length;
34+
35+
case Multiplication:
36+
double fractionalPart = (Math.abs(hashCode) * A) % 1;
37+
return (int) Math.floor(bucketArray.length * fractionalPart);
38+
39+
default:
40+
throw new IllegalStateException("Unknown Hash Function Type");
41+
}
42+
}
43+
44+
/**
45+
* Inserts or updates a key-value pair in the hash table.
46+
*
47+
* @param key the key to insert or update
48+
* @param value the value associated with the key
49+
*/
50+
public void put(String key, double value) {
51+
// Compute the index for this key using the hash function
52+
int index = hash(key);
53+
if (bucketArray[index] == null) {
54+
bucketArray[index] = new HashTableBucket();
55+
}
56+
57+
HashTableBucket bucket = bucketArray[index];
58+
HashTableEntry existingEntry = bucket.find(key);
59+
if (existingEntry != null) {
60+
// Key found, update value
61+
existingEntry.value = value;
62+
} else {
63+
// Check if adding a new entry would exceed the load factor and trigger rehashing if necessary
64+
if ((double) (size + 1) / bucketArray.length >= MAX_LOAD_FACTOR) {
65+
rehash();
66+
67+
// Recompute the index since the bucketArray length has changed after rehashing
68+
index = hash(key);
69+
if (bucketArray[index] == null) {
70+
bucketArray[index] = new HashTableBucket();
71+
}
72+
bucket = bucketArray[index];
73+
}
74+
75+
bucket.insertAtBeginning(key, value);
76+
size++;
77+
}
78+
}
79+
80+
// Doubles the size of the hash table and rehashes all existing entries
81+
private void rehash() {
82+
HashTableBucket[] oldTable = bucketArray;
83+
int newCapacity = nextPrime(oldTable.length * 2); // Find the next prime number greater than double the current length
84+
bucketArray = new HashTableBucket[newCapacity];
85+
size = 0;
86+
for (HashTableBucket bucket : oldTable) {
87+
if (bucket != null) {
88+
HashTableEntry current = bucket.head;
89+
while (current != null) {
90+
// Re-add each entry to the new table
91+
put(current.key, current.value);
92+
current = current.next;
93+
}
94+
}
95+
}
96+
}
97+
98+
// Utility method to find the next prime number greater than a given number
99+
private int nextPrime(int start) {
100+
for (int n = start; true; n++) {
101+
if (isPrime(n)) {
102+
return n;
103+
}
104+
}
105+
}
106+
107+
// Utility method to check if a number is prime
108+
private boolean isPrime(int number) {
109+
if (number <= 1) {
110+
return false;
111+
}
112+
for (int i = 2; i * i <= number; i++) {
113+
if (number % i == 0) {
114+
return false;
115+
}
116+
}
117+
return true;
118+
}
119+
120+
/**
121+
* Retrieves the value associated with a given key.
122+
*
123+
* @param key the key whose value is to be retrieved
124+
* @return the value associated with the key, or null if the key is not found
125+
*/
126+
public Double get(String key) {
127+
int index = hash(key);
128+
HashTableBucket bucket = bucketArray[index];
129+
if (bucket == null) {
130+
return null;
131+
}
132+
HashTableEntry entry = bucket.find(key);
133+
return entry != null ? entry.value : null; // Return value if key found, otherwise null
134+
}
135+
136+
/**
137+
* Removes a key-value pair from the hash table.
138+
*
139+
* @param key the key of the pair to be removed
140+
* @return true if the pair was successfully removed, false if the key was not found
141+
*/
142+
public boolean remove(String key) {
143+
int index = hash(key);
144+
if (bucketArray[index] == null) {
145+
return false; // No list exists at this index, so the key is not in the table
146+
}
147+
148+
HashTableBucket bucket = bucketArray[index];
149+
if (bucket.delete(key)) {
150+
size--;
151+
return true;
152+
}
153+
return false;
154+
}
155+
156+
// Returns the number of key-value pairs in the hash table
157+
public int size() {
158+
return size;
159+
}
160+
161+
/**
162+
* Prints the entire contents of the hash table.
163+
*/
164+
public void print() {
165+
for (int i = 0; i < bucketArray.length; i++) {
166+
System.out.print("[" + i + "]");
167+
HashTableBucket bucket = bucketArray[i];
168+
if (bucket != null) {
169+
bucket.print();
170+
}
171+
System.out.println();
172+
}
173+
}
174+
175+
/**
176+
* HashTableBucket class represents the linked list used in chaining
177+
*/
178+
private static class HashTableBucket {
179+
HashTableEntry head; // Head of the linked list
180+
181+
// Inserts a new entry at the beginning of the list
182+
void insertAtBeginning(String key, double value) {
183+
HashTableEntry newEntry = new HashTableEntry(key, value);
184+
newEntry.next = head;
185+
head = newEntry;
186+
}
187+
188+
/**
189+
* Deletes an entry with the specified key from the list.
190+
*
191+
* @param key The key of the entry to be deleted.
192+
* @return true if the entry was found and successfully deleted, false otherwise.
193+
*/
194+
boolean delete(String key) {
195+
HashTableEntry current = head;
196+
HashTableEntry prev = null;
197+
198+
while (current != null) {
199+
if (current.key.equals(key)) {
200+
// Key found, delete the entry
201+
if (prev == null) {
202+
head = current.next; // Deleting the first entry
203+
} else {
204+
prev.next = current.next; // Deleting a subsequent entry
205+
}
206+
return true; // Entry successfully deleted
207+
}
208+
prev = current;
209+
current = current.next;
210+
}
211+
212+
return false; // Key not found
213+
}
214+
215+
// Finds an entry by key in the list
216+
HashTableEntry find(String key) {
217+
HashTableEntry current = head;
218+
while (current != null) {
219+
if (current.key.equals(key)) {
220+
return current;
221+
}
222+
current = current.next;
223+
}
224+
return null; // Return null if key not found
225+
}
226+
227+
/**
228+
* Prints all the entries in this hash table bucket.
229+
*/
230+
void print() {
231+
HashTableEntry current = head;
232+
while (current != null) {
233+
current.print();
234+
current = current.next;
235+
}
236+
}
237+
}
238+
239+
/**
240+
* HashTableEntry class represents a key-value pair in the hash table
241+
*/
242+
private static class HashTableEntry {
243+
String key;
244+
double value;
245+
HashTableEntry next; // Reference to the next entry (node) in the linked list
246+
247+
HashTableEntry(String key, double value) {
248+
this.key = key;
249+
this.value = value;
250+
}
251+
252+
/**
253+
* Prints the key-value pair represented by this entry.
254+
*/
255+
void print() {
256+
System.out.print("->|" + key + ", " + value + "|");
257+
}
258+
}
259+
}

src/hashtable/HashTableMain.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package hashtable;
2+
3+
public class HashTableMain {
4+
/**
5+
* Demonstrates the usage of the HashTable class, including key operations
6+
* such as insertion, retrieval, removal, and automatic rehashing.
7+
*/
8+
public static void main(String[] args) {
9+
// Initialize the hash table with a small capacity of 5 for demonstration purposes.
10+
// This small initial capacity is chosen to illustrate how rehashing operates
11+
// when the hash table becomes full. In a practical application, especially for a dataset
12+
// like the chemical elements with a well-defined and relatively small set of items (118 confirmed elements),
13+
// an initial capacity between 150 and 200 could be more appropriate.
14+
// This provides ample space for all elements and minimizes the need for rehashing, enhancing performance.
15+
HashTable hashTable = new HashTable(5, HashFunctionType.Division);
16+
17+
// Insert key-value pairs into the hash table
18+
hashTable.put("Hydrogen", 1.008);
19+
hashTable.put("Helium", 4.0026);
20+
hashTable.put("Lithium", 6.94);
21+
22+
// Print the hash table's contents
23+
System.out.println("Initial Hash Table:");
24+
hashTable.print();
25+
26+
// Retrieve and print a specific value
27+
Double heliumWeight = hashTable.get("Helium");
28+
System.out.println("\nAtomic weight of Helium: " + heliumWeight);
29+
30+
// Update an existing key with a new value and print the hash table
31+
hashTable.put("Helium", 4.002602);
32+
System.out.println("\nAfter updating Helium's atomic weight:");
33+
hashTable.print();
34+
35+
// Remove an entry and print the hash table
36+
hashTable.remove("Lithium");
37+
System.out.println("\nAfter removing Lithium:");
38+
hashTable.print();
39+
40+
// Insert more entries to trigger rehashing
41+
hashTable.put("Beryllium", 9.0122);
42+
hashTable.put("Boron", 10.81);
43+
hashTable.put("Carbon", 12.011);
44+
hashTable.put("Nitrogen", 14.007);
45+
hashTable.put("Oxygen", 15.999);
46+
47+
System.out.println("\nAfter adding more elements and triggering rehashing:");
48+
hashTable.print();
49+
}
50+
}

0 commit comments

Comments
 (0)