Algorithmen & Datenstrukturen mit Java: Beispielklasse für einfache Hash-Tabellen |
1package ds.interfaces;
2
3/** Simple interface for maps
4 */
5
6import java.util.Iterator;
7
8import ds.util.Invariant;
9import ds.util.Function2;
10
11import ds.util.K; // example class for keys
12import ds.util.V; // example class for values
13import ds.util.KV; // key value pair
14
15public
16 interface Map
17 extends Iterable<KV>,
18 Invariant {
19
20 boolean isEmpty();
21 boolean member(K k);
22 V lookup(K k);
23 int size();
24 KV findMin();
25 KV findMax();
26 Map insert(K k, V v);
27 Map remove(K k);
28 Map union(Map m2);
29 Map difference(Map m2);
30 Map unionWith(Function2<V,V,V> op, Map m2);
31 Map differenceWith(Function2<V,V,V> op, Map m2);
32 Map copy();
33
34 // inherited
35
36 // public Iterator<KV> iterator();
37 // public inv();
38}
1package ds.destructive.map;
2
3/** Implementation of maps with hash maps implemeted as arrays
4
5 hash maps require a a hash function on the
6 keys of a map. These hashes are used for indexing the
7 hash table.
8
9 This is a DESTRUCTIVE implementation.
10*/
11
12import ds.interfaces.Map;
13
14import ds.util.K; // example class for keys
15import ds.util.V; // example class for values
16import ds.util.KV; // key value pair
17import static ds.util.KV.mkPair;
18
19import ds.util.Function2;
20import ds.util.Invariant;
21import ds.util.Pair;
22import ds.util.Predicate;
23
24import java.util.Iterator;
25
26import static ds.util.Undef.undefined;
27
28//----------------------------------------
29
30public
31 class SimpleHashMap
32 implements Map {
33
34 //----------------------------------------
35
36 private int card;
37 private KV [] elems;
38
39 SimpleHashMap (int len) {
40 card = 0;
41 elems = new KV [len];
42 ++cntMap;
43 }
44
45 //----------------------------------------
46 // the smart constructors
47
48 // empty list
49 public static SimpleHashMap empty() {
50 return
51 empty(16); // why 16?
52 }
53
54 public static SimpleHashMap empty(int length) {
55 int l = 16;
56 while (l < length) l *= 2;
57
58 // length of hash table is always a power of 2
59 // for efficient modulo operations
60
61 return
62 new SimpleHashMap(length);
63 }
64
65 public static
66 SimpleHashMap fromIterator(Iterator<KV> elems) {
67
68 SimpleHashMap res = empty();
69 while ( elems.hasNext() ) {
70 KV p = elems.next();
71 res = res.insert(p);
72 }
73 return
74 res;
75 }
76
77 public boolean isEmpty() {
78 return size() == 0;
79 }
80
81 public boolean member(K k) {
82 return
83 lookup(k) != null;
84 }
85
86 public int size() {
87 return
88 card;
89 }
90
91 public V lookup(K k) {
92 int ix = keyToHash(k);
93 KV kv = elems[ix];
94
95 while ( kv != null
96 &&
97 ! kv.fst.equalTo(k)
98 ) {
99 incr(ix);
100 kv = elems[ix];
101 }
102
103 return
104 kv == null ? null : kv.snd;
105 }
106
107 public KV findMin() {
108 return
109 undefined("findMin not implemented");
110 }
111
112 public KV findMax() {
113 return
114 undefined("findMax not implemented");
115 }
116
117 public SimpleHashMap insert(K k, V v) {
118 return
119 insert(mkPair(k,v));
120 }
121
122 public SimpleHashMap insert(KV p) {
123 K k = p.fst;
124 int ix = keyToHash(k);
125 KV kv = elems[ix];
126
127 while ( kv != null
128 &&
129 ! kv.fst.equalTo(k)
130 ) {
131 incr(ix);
132 kv = elems[ix];
133 }
134
135 if (kv == null) {
136 // new elem
137 elems[ix] = p;
138 ++card;
139 } else {
140 // update of value
141 elems[ix] = p;
142 }
143
144 return
145 checkExpand();
146 }
147
148 public SimpleHashMap remove(K k) {
149 return
150 undefined("remove not implemented");
151 }
152
153 public SimpleHashMap union(Map m2) {
154 return
155 unionWith(const2, m2);
156 }
157
158 public
159 SimpleHashMap unionWith(Function2<V,V,V> op,
160 Map m2) {
161 return undefined("unionWith not implemented");
162 }
163
164 public
165 SimpleHashMap difference(Map m2) {
166 return
167 differenceWith(null2, m2);
168 }
169
170 public
171 SimpleHashMap differenceWith(Function2<V,V,V> op,
172 Map m2) {
173 return
174 undefined("differenceWith not implemented");
175 }
176
177 public SimpleHashMap copy() {
178 return
179 this;
180 }
181
182 public Iterator<KV> iterator() {
183 ++cntIter;
184 return
185 new HashMapIterator(this);
186 }
187
188 public boolean inv() {
189 for (int i = 0; i < elems.length; ++i) {
190 if (elems[i] != null) {
191 int ix = keyToHash(elems[i].fst);
192
193 /* all entries in hashtable
194 in the intervall [ix..i]
195 must be filled, otherwise the hash does not
196 fit to the position
197 */
198 int j = i;
199 while (j != ix) {
200 decr(j);
201 if (elems[j] == null)
202 // unused cell found
203 return
204 false;
205 }
206 }
207 }
208
209 return true;
210 }
211
212 //----------------------------------------
213 // internal methods
214
215 private static Function2<V,V,V> const2
216 = new Function2<V,V,V>() {
217 public V apply(V x, V y) {
218 return y;
219 }
220 };
221
222 private static Function2<V,V,V> null2
223 = new Function2<V,V,V>() {
224 public V apply(V x, V y) {
225 return null;
226 }
227 };
228
229 private int keyToHash(K k) {
230 return
231 k.hash() & (elems.length - 1);
232 }
233
234 private int incr(int i) {
235 ++i;
236 return
237 i == elems.length ? 0 : i;
238 }
239
240 private int decr(int i) {
241 return
242 (i == 0 ? elems.length : i) - 1;
243 }
244
245 private SimpleHashMap checkExpand() {
246 if (card > elems.length) {
247 return
248 reorganize(2 * elems.length);
249 }
250 return this;
251 }
252
253 private SimpleHashMap reorganize(int newSize) {
254 SimpleHashMap nm = empty(newSize);
255 for (int i = 0; i < elems.length; ++i) {
256 nm = nm.insert(elems[i]);
257 }
258 return
259 nm;
260 }
261
262 private static
263 class HashMapIterator
264 extends ds.util.Iterator<KV> {
265
266 SimpleHashMap map;
267 int len;
268 int ix;
269
270 HashMapIterator(SimpleHashMap m) {
271 map = m;
272 ix = 0;
273 len = m.elems.length;
274 advance();
275 ++cntIter;
276 }
277
278 public boolean hasNext() {
279 return
280 ix < len;
281 }
282
283 private void advance() {
284 while ( ix < len
285 &&
286 map.elems[ix] == null
287 ) {
288 ++ix;
289 }
290 }
291
292 public KV next() {
293 if ( ix == len )
294 return
295 undefined("empty hashmap");
296 KV res = map.elems[ix];
297 ++ix;
298 advance();
299 return
300 res;
301 }
302 }
303
304 //----------------------------------------
305 // profiling
306
307 private static int cntMap = 0;
308 private static int spcMap = 0;
309 private static int cntIter = 0;
310
311 public static String stats() {
312 return
313 "stats for ds.destructive.map.SimpleHashMap:\n" +
314 "# new SimpleHashMap() : " + cntMap + "\n" +
315 "# words SimpleHashMap() : " + spcMap + "\n" +
316 "# new Iterator() : " + cntIter + "\n";
317 }
318
319 public String objStats() {
320 int o =
321 1 + // SimpleHashMap
322 1 + // array
323 card; // KV
324
325 int f =
326 2 + // SimpleHashMap
327 elems.length + 1 + // array
328 card * 2; // KV
329 int m = o + f;
330
331 return
332 "mem stats for ds.destructive.map.SimpleHashMap object:\n" +
333 "# objects : " + o + "\n" +
334 "# fields : " + f + "\n" +
335 "# mem words : " + m + "\n";
336 }
337}
|
Letzte Änderung: 11.01.2017 | © Prof. Dr. Uwe Schmidt |