Skip to content

Commit b46fd6a

Browse files
committed
Add hash table data structure implementation
1 parent 16b5843 commit b46fd6a

3 files changed

Lines changed: 184 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ To-do
1414
- [ ] Doubly linked list
1515
- [x] Stack
1616
- [x] Queue
17-
- [ ] Hash table
17+
- [x] Hash table
1818

1919
### Trees
2020

src/main/lists/HashFunctions.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import java.util.function.ToIntFunction;
2+
3+
public class HashFunctions {
4+
public static class ModularHash implements ToIntFunction<Integer> {
5+
int m;
6+
7+
public ModularHash(int m) {
8+
this.m = m;
9+
}
10+
11+
public int applyAsInt(Integer k) {
12+
return k % this.m;
13+
}
14+
}
15+
16+
public static class CommonModularHash implements ToIntFunction<Integer> {
17+
HashTable<?, ?> hashTable;
18+
19+
public CommonModularHash(HashTable<?, ?> hashTable) {
20+
this.hashTable = hashTable;
21+
}
22+
23+
public int applyAsInt(Integer k) {
24+
return k % this.hashTable.getCapacity();
25+
}
26+
}
27+
}

src/main/lists/HashTable.java

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import java.util.function.ToIntFunction;
2+
3+
class HashTableNode<K, V> {
4+
K key;
5+
V value;
6+
HashTableNode<K, V> next;
7+
8+
HashTableNode(K key, V value, HashTableNode<K, V> next) {
9+
this.key = key;
10+
this.value = value;
11+
this.next = next;
12+
}
13+
}
14+
15+
@SuppressWarnings("unchecked")
16+
public class HashTable<K, V> {
17+
Object[] buckets;
18+
float loadFactor = 0.75f; // The maximum load factor
19+
ToIntFunction<Integer> hashFunction = k -> k % this.buckets.length; // h(k)
20+
int length;
21+
22+
public HashTable() {
23+
this.buckets = new Object[1 << 4]; // Start with 16 buckets by default
24+
this.length = 0;
25+
}
26+
27+
public HashTable(int initialCapacity) {
28+
this.buckets = new Object[initialCapacity];
29+
this.length = 0;
30+
}
31+
32+
public HashTable(int initialCapacity, float loadFactor) {
33+
if (loadFactor <= 0)
34+
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
35+
36+
this.buckets = new Object[initialCapacity];
37+
this.loadFactor = loadFactor;
38+
this.length = 0;
39+
}
40+
41+
public int getLength() {
42+
return this.length;
43+
}
44+
45+
public int getCapacity() {
46+
return this.buckets.length;
47+
}
48+
49+
public ToIntFunction<Integer> getHashFunction() {
50+
return this.hashFunction;
51+
}
52+
53+
public void setHashFunction(ToIntFunction<Integer> hashFunction) {
54+
this.hashFunction = hashFunction;
55+
}
56+
57+
private boolean put(HashTableNode<K, V> newNode, Object[] buckets) {
58+
newNode.next = null;
59+
int index = this.hashFunction.applyAsInt(newNode.key.hashCode());
60+
61+
if (buckets[index] == null) {
62+
buckets[index] = newNode;
63+
return true;
64+
}
65+
else {
66+
HashTableNode<K, V> node = (HashTableNode<K, V>) buckets[index];
67+
68+
while (true) {
69+
if (node.key.equals(newNode.key)) {
70+
node.value = newNode.value;
71+
return false;
72+
}
73+
74+
if (node.next != null)
75+
node = node.next;
76+
else
77+
break;
78+
}
79+
80+
node.next = newNode;
81+
return true;
82+
}
83+
}
84+
85+
public void put(K key, V value) {
86+
if ((this.length + 1) / this.buckets.length > this.loadFactor)
87+
this.expand();
88+
89+
if (this.put(new HashTableNode<K, V>(key, value, null), this.buckets))
90+
this.length++;
91+
}
92+
93+
public boolean remove(K key) {
94+
int index = this.hashFunction.applyAsInt(key.hashCode());
95+
HashTableNode<K, V> node = (HashTableNode<K, V>) this.buckets[index];
96+
97+
if (node == null)
98+
return false;
99+
100+
if (node.key.equals(key)) {
101+
this.buckets[index] = node.next;
102+
return true;
103+
}
104+
105+
while (node.next != null) {
106+
if (node.next.key.equals(key)) {
107+
node.next = node.next.next;
108+
return true;
109+
}
110+
111+
node = node.next;
112+
}
113+
114+
return false;
115+
}
116+
117+
public V get(K key) {
118+
int index = this.hashFunction.applyAsInt(key.hashCode());
119+
HashTableNode<K, V> node = (HashTableNode<K, V>) this.buckets[index];
120+
121+
while (node != null) {
122+
if (node.key.equals(key))
123+
return node.value;
124+
125+
node = node.next;
126+
}
127+
128+
return null;
129+
}
130+
131+
private void rehash(int newCapacity) {
132+
Object[] newBuckets = new Object[newCapacity];
133+
134+
for (Object bucket: this.buckets) {
135+
HashTableNode<K, V> node = (HashTableNode<K, V>) bucket;
136+
137+
if (node == null)
138+
continue;
139+
else
140+
while (node.next != null) {
141+
this.put(node, newBuckets);
142+
node = node.next;
143+
}
144+
}
145+
146+
this.buckets = newBuckets;
147+
}
148+
149+
private void expand() {
150+
this.rehash(this.buckets.length * 2);
151+
}
152+
153+
public void shrink(float minimumLoadFactor) {
154+
this.rehash((int) Math.ceil(this.length / minimumLoadFactor));
155+
}
156+
}

0 commit comments

Comments
 (0)