-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAbstractHashMap.java
159 lines (143 loc) · 5.98 KB
/
AbstractHashMap.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
/*
* Copyright 2014, Michael T. Goodrich, Roberto Tamassia, Michael H. Goldwasser
*
* Developed for use with the book:
*
* Data Structures and Algorithms in Java, Sixth Edition
* Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
* John Wiley & Sons, 2014
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.ArrayList;
import java.util.Random;
/**
* An abstract base class supporting Map implementations that use hash
* tables with MAD compression.
*
* The base class provides the following means of support:
* 1) Support for calculating hash values with MAD compression
* 2) Support for resizing table when load factor reaches 1/2
*
* Subclass is responsible for providing abstract methods:
* createTable(), bucketGet(h,k), bucketPut(h,k,v),
* bucketRemove(h,k), and entrySet()
* and for accurately maintaining the protected member, n,
* to reflect changes within bucketPut and bucketRemove.
*
* @author Michael T. Goodrich
* @author Roberto Tamassia
* @author Michael H. Goldwasser
*/
public abstract class AbstractHashMap<K,V> extends AbstractMap<K,V> {
protected int n = 0; // number of entries in the dictionary
protected int capacity; // length of the table
private int prime; // prime factor
private long scale, shift; // the shift and scaling factors
/** Creates a hash table with the given capacity and prime factor. */
public AbstractHashMap(int cap, int p) {
prime = p;
capacity = cap;
Random rand = new Random();
scale = rand.nextInt(prime-1) + 1;
shift = rand.nextInt(prime);
createTable();
}
/** Creates a hash table with given capacity and prime factor 109345121. */
public AbstractHashMap(int cap) { this(cap, 109345121); } // default prime
/** Creates a hash table with capacity 17 and prime factor 109345121. */
public AbstractHashMap() { this(17); } // default capacity
// public methods
/**
* Tests whether the map is empty.
* @return true if the map is empty, false otherwise
*/
@Override
public int size() { return n; }
/**
* Returns the value associated with the specified key, or null if no such entry exists.
* @param key the key whose associated value is to be returned
* @return the associated value, or null if no such entry exists
*/
@Override
public V get(K key) { return bucketGet(hashValue(key), key); }
/**
* Removes the entry with the specified key, if present, and returns
* its associated value. Otherwise does nothing and returns null.
* @param key the key whose entry is to be removed from the map
* @return the previous value associated with the removed key, or null if no such entry exists
*/
@Override
public V remove(K key) { return bucketRemove(hashValue(key), key); }
/**
* Associates the given value with the given key. If an entry with
* the key was already in the map, this replaced the previous value
* with the new one and returns the old value. Otherwise, a new
* entry is added and null is returned.
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with the key (or null, if no such entry)
*/
@Override
public V put(K key, V value) {
V answer = bucketPut(hashValue(key), key, value);
if (n > capacity / 2) // keep load factor <= 0.5
resize(2 * capacity - 1); // (or find a nearby prime)
return answer;
}
// private utilities
/** Hash function applying MAD method to default hash code. */
protected int hashValue(K key) {
return (int) ((Math.abs(key.hashCode()*scale + shift) % prime) % capacity);
}
/** Updates the size of the hash table and rehashes all entries. */
private void resize(int newCap) {
ArrayList<Entry<K,V>> buffer = new ArrayList<>(n);
for (Entry<K,V> e : entrySet())
buffer.add(e);
capacity = newCap;
createTable(); // based on updated capacity
n = 0; // will be recomputed while reinserting entries
for (Entry<K,V> e : buffer)
put(e.getKey(), e.getValue());
}
// protected abstract methods to be implemented by subclasses
/** Creates an empty table having length equal to current capacity. */
protected abstract void createTable();
/**
* Returns value associated with key k in bucket with hash value h.
* If no such entry exists, returns null.
* @param h the hash value of the relevant bucket
* @param k the key of interest
* @return associate value (or null, if no such entry)
*/
protected abstract V bucketGet(int h, K k);
/**
* Associates key k with value v in bucket with hash value h, returning
* the previously associated value, if any.
* @param h the hash value of the relevant bucket
* @param k the key of interest
* @param v the value to be associated
* @return previous value associated with k (or null, if no such entry)
*/
protected abstract V bucketPut(int h, K k, V v);
/**
* Removes entry having key k from bucket with hash value h, returning
* the previously associated value, if found.
* @param h the hash value of the relevant bucket
* @param k the key of interest
* @return previous value associated with k (or null, if no such entry)
*/
protected abstract V bucketRemove(int h, K k);
}