-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMyHashMap (1).java
337 lines (328 loc) · 8.4 KB
/
MyHashMap (1).java
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
import java.util.*;
/**
* A Hash table implementation. Uses an array of LinkedList<MyEntry> as a storage.
*
* @param <K> generic type for Keys.
* @param <V> generic type for Values.
*/
public class MyHashMap<K, V> {
/**
* Represents a key, value pairing.
*
*/
public class MyEntry {
protected K key;
protected V value;
@Override
/**
* Gives the hashcode of a MyEntry object.
* @return the hashcode of the MyEntry's key.
*/
public int hashCode() {
return key.hashCode();
}
/**
* Tests whether this object is equivalent to a specified other.
* @param obj the other object.
* @return true if the keys are equivalent.
*/
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (obj == null || this == null) return false;
MyEntry other = (MyEntry) obj;
if (key.equals(other.key)) return true;
return false;
}
/**
* Constructs a MyEntry object with given key and value.
* @param key the key to be stored.
* @param value the value to be stored.
*/
public MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
/**
* Gives a String representation of this object.
* @return the String representation.
*/
public String toString() {
return "("+key+", "+value+")";
}
}
private LinkedList<MyEntry> table[];
private int size;
private float loadFactor;
private ArrayList<Integer> primes = new ArrayList<Integer>();
/**
* Constructs a new MyHashMap object.
* @param capacity the size of the array.
* @param loadFactor the specified load factor. The array will resize when the load factor is reached.
*/
@SuppressWarnings("unchecked")
public MyHashMap(int capacity, float loadFactor) {
table = (LinkedList<MyEntry> []) new LinkedList[capacity];
this.loadFactor = loadFactor;
for (int i=0; i<table.length; i++) {
table[i] = new LinkedList<MyEntry>();
}
}
/**
* Constructs a MyHashMap with capacity 11 and load factor 0.75.
*/
public MyHashMap() {
this(11, (float) 0.75);
primes.add(11);
primes.add(23);
primes.add(47);
primes.add(97);
primes.add(197);
primes.add(397);
primes.add(797);
primes.add(1597);
primes.add(3203);
primes.add(6421);
primes.add(12853);
primes.add(25717);
primes.add(51437);
primes.add(102877);
primes.add(205759);
primes.add(411527);
primes.add(823117);
primes.add(1646237);
primes.add(3292489);
primes.add(6584983);
primes.add(13169977);
primes.add(26339969);
primes.add(52679969);
primes.add(105359939);
primes.add(210719881);
primes.add(421439783);
primes.add(842879579);
primes.add(1685759167);
}
/**
* Gives the number of MyEntries in the array.
* @return number of MyEntry objects in the array.
*/
public int size() {
return size;
}
/**
* Tests whether or not the array is empty.
* @return true if empty, false otherwise.
*/
public boolean isEmpty() {
if (size == 0) return true;
else return false;
}
/**
* Removes all objects from the array.
*/
public void clear() {
for (int i=0; i<table.length; i++) {
table[i].clear();
}
}
/**
* Gives a String representation of the array.
* @return said String representation.
*/
public String toString() {
String ret = "";
for (int i=0; i<table.length; i++) {
ret+=("Bucket "+i+": "+table[i]+"\n");
}
return ret;
}
/**
* Adds a key, value mapping to the array. If the key already is contained, the value will be updated.
* @param key the key to be added.
* @param value the value to be added.
* @return the previous value if the key already was contained, null otherwise.
*/
public V put(K key, V value) {
MyEntry entry = new MyEntry(key, value);
int hashCode = Math.abs(key.hashCode());
int mapping = hashCode%(table.length);
LinkedList<MyEntry> bucket = table[mapping];
V ret = null;
if (bucket.contains(entry)) {
int index = bucket.indexOf(entry);
ret = bucket.get(index).value;
bucket.set(index, entry);
}
else
bucket.add(entry);
size++;
if (((double)size)/((double)table.length) >= loadFactor)
resize();
return ret;
}
/**
* Gives the value associated with a specified key.
* @param key the specified key.
* @return the value associated. Null if the key is not found.
*/
public V get(K key) {
V ret = null;
int hashCode = Math.abs(key.hashCode());
int mapping = hashCode%(table.length);
LinkedList<MyEntry> bucket = table[mapping];
for (int i=0; i<bucket.size(); i++) {
MyEntry cur = bucket.get(i);
if (cur.key.equals(key)) {
ret = cur.value;
}
}
return ret;
}
/**
* Removes a specified object from the array.
* @param key the key corresponding to the MyEntry to be removed.
* @return the value associated with the removed key.
*/
public V remove(K key) {
V ret = null;
int hashCode = Math.abs(key.hashCode());
int mapping = hashCode%(table.length);
LinkedList<MyEntry> bucket = table[mapping];
for (int i=0; i<bucket.size(); i++) {
MyEntry cur = bucket.get(i);
if (cur.key.equals(key)) {
ret = cur.value;
bucket.remove(cur);
}
}
size--;
return ret;
}
/**
* Finds whether or not the array contains a given key.
* @param key the key to be tested.
* @return true if found, false if not.
*/
public boolean containsKey(K key) {
boolean ret = false;
int hashCode = Math.abs(key.hashCode());
int mapping = hashCode%(table.length);
LinkedList<MyEntry> bucket = table[mapping];
MyEntry test = new MyEntry(key, null);
if (bucket.contains(test)) {
ret = true;
}
return ret;
}
/**
* Finds whether or not the array contains a given value.
* @param value the value to be tested.
* @return true if found, false if not.
*/
public boolean containsValue(V value) {
boolean ret = false;
for (int i=0; i<table.length; i++) {
LinkedList<MyEntry> bucket = table[i];
for (int j=0; j<bucket.size(); j++) {
MyEntry entry = bucket.get(j);
if (entry.value.equals(value))
ret = true;
}
}
return ret;
}
/**
* Iterates over the MyEntry objects in the array, looking at their keys.
* @return a keys iterator.
*/
public Iterator<K> keys() {
return new Iterator<K>() {
int bucketIndex = 0;
LinkedList<MyEntry> bucket = table[bucketIndex];
Iterator<MyEntry> listIt = bucket.iterator();
MyEntry cur;
/**
* Finds whether or not there is a next MyEntry object in the array.
* @return
*/
@Override
public boolean hasNext() {
if (listIt.hasNext())
return true;
else if (bucketIndex == (table.length-1)) {
return false;
}
else {
for (int i=bucketIndex+1; i<table.length; i++) {
if (!table[i].isEmpty())
return true;
}
}
return false;
}
/**
* Gives the key associated with the next MyEntry object in the array. Throws a NoSuchElementException if the array has been completely iterated.
* @return the key associated with the next MyEntry object.
*/
@Override
public K next() {
K ret = null;
if (listIt.hasNext()) {
cur = listIt.next();
ret = cur.key;
}
else if (hasNext()) {
for (int i=bucketIndex+1; i<table.length; i++) {
if (!table[i].isEmpty()) {
bucketIndex = i;
bucket = table[bucketIndex];
listIt = bucket.iterator();
cur = listIt.next();
ret = cur.key;
break;
}
}
}
else throw new NoSuchElementException("All buckets iterated.");
return ret;
}
/**
* Removes the current MyEntry.
*/
@Override
public void remove() {
bucket.remove(cur);
}
};
}
/**
* Resizes the array to the next largest prime number that is at least double the current array size.
*/
public void resize() {
MyHashMap<K,V> tmp = new MyHashMap<K,V>(helper(table.length), (float) 0.75);
Iterator<K> it = keys();
while (it.hasNext()) {
K key = it.next();
V value = get(key);
tmp.put(key, value);
}
this.table = tmp.table;
this.size = tmp.size;
this.loadFactor = tmp.loadFactor;
}
/**
* Gives the next largest prime number that is at least double the current array size.
* @param i
* @return
*/
public int helper(int i) {
int ret = -1;
for (int j=0; j<primes.size(); j++) {
if (primes.get(j) > i) {
ret = primes.get(j);
break;
}
}
return ret;
}
}