forked from TheAlgorithms/Java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinearProbingHashMap.java
More file actions
169 lines (145 loc) · 4.85 KB
/
LinearProbingHashMap.java
File metadata and controls
169 lines (145 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package com.thealgorithms.datastructures.hashmap.hashing;
import java.util.ArrayList;
/**
* 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.
*
* <p>
* 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.
* </p>
*
* <p>
* This implementation supports basic operations such as:
* <ul>
* <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>
* <li><b>get(Key key)</b>: Retrieves the value associated with the given key.</li>
* <li><b>delete(Key key)</b>: Removes the key and its associated value from the hash table.</li>
* <li><b>contains(Key key)</b>: Checks if the hash table contains a given key.</li>
* <li><b>size()</b>: Returns the number of key-value pairs in the hash table.</li>
* <li><b>keys()</b>: Returns an iterable collection of keys stored in the hash table.</li>
* </ul>
* </p>
*
* <p>
* 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.
* </p>
*
* @see <a href="https://en.wikipedia.org/wiki/Linear_probing">Linear Probing Hash Table</a>
*
* @param <Key> the type of keys maintained by this map
* @param <Value> the type of mapped values
*/
@SuppressWarnings("rawtypes")
public class LinearProbingHashMap<Key extends Comparable<Key>, Value> extends Map<Key, Value> {
private int hsize; // size of 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];
values = (Value[]) new Object[size];
}
@Override
public boolean put(Key key, Value value) {
if (key == null) {
return false;
}
if (size > hsize / 2) {
resize(2 * hsize);
}
int keyIndex = hash(key, hsize);
for (; keys[keyIndex] != null; keyIndex = increment(keyIndex)) {
if (key.equals(keys[keyIndex])) {
values[keyIndex] = value;
return true;
}
}
keys[keyIndex] = key;
values[keyIndex] = value;
size++;
return true;
}
@Override
public Value get(Key key) {
if (key == null) {
return null;
}
for (int i = hash(key, hsize); keys[i] != null; i = increment(i)) {
if (key.equals(keys[i])) {
return values[i];
}
}
return null;
}
@Override
public boolean delete(Key key) {
if (key == null || !contains(key)) {
return false;
}
int i = hash(key, hsize);
while (!key.equals(keys[i])) {
i = increment(i);
}
keys[i] = null;
values[i] = null;
i = increment(i);
while (keys[i] != null) {
// Save the key and value for rehashing
Key keyToRehash = keys[i];
Value valToRehash = values[i];
keys[i] = null;
values[i] = null;
size--;
put(keyToRehash, valToRehash);
i = increment(i);
}
size--;
if (size > 0 && size <= hsize / 8) {
resize(hsize / 2);
}
return true;
}
@Override
public boolean contains(Key key) {
return get(key) != null;
}
@Override
int size() {
return size;
}
@Override
Iterable<Key> keys() {
ArrayList<Key> listOfKeys = new ArrayList<>(size);
for (int i = 0; i < hsize; i++) {
if (keys[i] != null) {
listOfKeys.add(keys[i]);
}
}
listOfKeys.sort(Comparable::compareTo);
return listOfKeys;
}
private int increment(int i) {
return (i + 1) % hsize;
}
private void resize(int newSize) {
LinearProbingHashMap<Key, Value> tmp = new LinearProbingHashMap<>(newSize);
for (int i = 0; i < hsize; i++) {
if (keys[i] != null) {
tmp.put(keys[i], values[i]);
}
}
this.keys = tmp.keys;
this.values = tmp.values;
this.hsize = newSize;
}
}