AuD
Lecture 'Algorithmen und Datenstrukturen' (code examples)
HashMap.java
Go to the documentation of this file.
1package aud;
2
3import java.util.Iterator;
4
31public class HashMap<Key,Value> {
32
33 // TODO define ADT AbstractUnorderedMap (extends AbstractMap)
34 // TODO define unit test for HashMap
35
36 // primes stolen from an older version of gcc's STL
37 static final int PRIMES[]={
38 31, 53, 97, 193, 389,
39 769, 1543, 3079, 6151, 12289,
40 24593, 49157, 98317, 196613, 393241,
41 786433, 1572869, 3145739, 6291469, 12582917,
42 25165843, 50331653, 100663319, 201326611, 402653189,
43 805306457, 1610612741
44 };
46 static int getNextPrime(int n) {
47 for (int p : PRIMES)
48 if (p>=n)
49 return p;
50 throw new RuntimeException("table size exceeds limits"); // unrealistic!
51 }
52
54 class Bucket {
55 Bucket(Key key,Value value) {
56 this.key=key;
57 this.value=value;
58 }
59 Key key;
60 Value value;
61 Bucket next=null;
62 };
63
65 public class Entry {
66 Entry(Key key,Value value) {
67 this.key=key;
68 this.value=value;
69 }
70 public Key key;
71 public Value value;
72 }
73
75 public class Entries implements Iterable<Entry> {
76 HashMap<Key,Value> hashmap_;
77 Entries(HashMap<Key,Value> hashmap) { hashmap_=hashmap; }
78 @Override public Iterator<Entry> iterator() {
79 return new EntryIterator(hashmap_);
80 }
81 }
82
84 class EntryIterator implements Iterator<Entry> {
85 HashMap<Key,Value> hashmap_;
86 int idx_;
87 Bucket bucket_=null;
88
89 @SuppressWarnings("unchecked")
90 EntryIterator(HashMap<Key,Value> hashmap) {
91 hashmap_=hashmap;
92 // find first entry
93 for (idx_=0;idx_<hashmap_.table_.length;++idx_) {
94 if ((bucket_=(Bucket) hashmap_.table_[idx_])!=null)
95 break;
96 }
97 }
98
100 @SuppressWarnings("unchecked") void advance() {
101 assert(bucket_!=null);
102 bucket_=bucket_.next; // we may reach the end of the list
103
104 while (bucket_==null) {
105 if (++idx_>=hashmap_.table_.length)
106 break;
107 bucket_=(Bucket) hashmap_.table_[idx_];
108 }
109 }
110
111 @Override public boolean hasNext() {
112 return bucket_!=null;
113 }
114
115 @Override public Entry next() {
116 assert(bucket_!=null);
117 Entry entry=new Entry(bucket_.key,bucket_.value);
118 advance();
119 return entry;
120 }
121
122 @Override public void remove() {
123 throw new UnsupportedOperationException();
124 }
125 }
126
127
128 Object table_[] = null; // stores Bucket instances (Java generics suck!)
129 double maxLoad_ = 0.75;
130 int size_ = 0;
131
135 public HashMap(int size) {
136 int n=(int) ((double) size/maxLoad_);
137 if (n<size) n=size;
138 n=getNextPrime(n);
139 table_=new Object[n];
140 }
141
143 public HashMap() {
144 this(PRIMES[0]);
145 }
146
148 public int getHashtableSize() {
149 return table_.length;
150 }
151
153 public int size() { return size_; }
154
156 public boolean is_empty() { return size_==0; }
157
159 public double getLoadFactor() {
160 return (double) size_/(double) table_.length;
161 }
162
164 void setMaximumLoadFactor(double alpha) {
165 if (alpha<maxLoad_ && getLoadFactor()>alpha)
166 rehash(alpha);
167
168 maxLoad_=alpha;
169 }
170
175 public void reserve(int size) {
176 if (size>size_)
177 rehash((int) ((double) size)/maxLoad_);
178 }
179
181 void rehash(double alpha) {
182 rehash((int) (alpha* (double) size_));
183 }
184
188 @SuppressWarnings("unchecked")
189 void rehash(int newSize) {
190 int n=getNextPrime(newSize);
191 System.err.println("INFO: rehash "+table_.length+" -> "+n+
192 " ("+size_+" entries, load factor "+getLoadFactor()+")");
193 HashMap<Key,Value> ht=new HashMap<Key,Value>(n);
194 for (Object position : table_) {
195 for (Bucket b=(Bucket) position;b!=null;b=b.next) {
196 ht._set(b.key,b.value);
197 }
198 }
199 // steal data from ht
200 table_=ht.table_;
201 size_=ht.size_;
202 }
203
207 public Entries entries() { return new Entries(this); }
208
216 @SuppressWarnings("unchecked")
217 Value _set(Key key,Value value) {
218 int hash = key.hashCode();
219 hash = hash < 0 ? -hash : hash;
220 int i=hash % table_.length;
221 if (table_[i]==null) {
222 if (value!=null) // (key,null) is never stored
223 table_[i]=new Bucket(key,value);
224 }
225 else { // collision
226 Bucket tail=null;
227 for (Bucket b=(Bucket) table_[i];b!=null;b=b.next) {
228 if (b.key.equals(key)) { // Is key already in list?
229 Value old=b.value;
230 b.value=value; // YES: change
231
232 if (value==null) { // special case: remove
233 if (tail==null)
234 table_[i]=b.next;
235 else
236 tail.next=b.next;
237 --size_;
238 }
239
240 return old;
241 }
242 tail=b;
243 }
244 assert(tail!=null);
245 tail.next=new Bucket(key,value); // NO: insert at end of list
246 }
247 ++size_;
248
249 return null;
250 }
251
260 public Value insert(Key key,Value value) {
261 Value v=_set(key,value);
262 if (v==null && value!=null) { // increased size()?
263 if (getLoadFactor()>maxLoad_)
264 rehash(table_.length*2); // rehash if maximum load factor exceeded
265 }
266 return v;
267 }
268
273 public Value remove(Key key) {
274 return _set(key,null);
275 }
276
280 @SuppressWarnings("unchecked")
281 public Value find(Key key) {
282 int hash=key.hashCode();
283 hash = hash < 0 ? -hash : hash;
284 int i=hash % table_.length;
285 if (table_[i]!=null) {
286 for (Bucket b=(Bucket) table_[i];b!=null;b=b.next) {
287 if (b.key.equals(key))
288 return b.value;
289 }
290 }
291 return null;
292 }
293
295 public boolean contains(Key key) {
296 return find(key)!=null;
297 }
298
299 @Override public String toString() {
300 String s="{ ";
301 for (Entry entry : entries())
302 s+=(entry.key.toString()+"=>"+entry.value+",");
303 s=s.substring(0,s.length()-1);
304 return s+=" };";
305 }
306
307
308 public static void main(String args[]) {
310
311 map.insert("a",1);
312 map.insert("b",2);
313 map.insert("c",3);
314 map.insert("d",4);
315 map.insert("e",5);
316 map.insert("f",6);
317 map.insert("g",7);
318 map.insert("h",8);
319
320 for (HashMap<String,Integer>.Entry entry : map.entries()) {
321 System.out.println(entry.key+" => "+entry.value);
322 }
323 System.out.println(map);
324 map.remove("a");
325 System.out.println(map);
326 System.out.println(map.find("c"));
327 System.out.println(map.find("x"));
328 }
329}
provide HashMap iterator over key-value pairs (Entry)
Definition: HashMap.java:75
Iterator< Entry > iterator()
Definition: HashMap.java:78
entry (key,value) in HashMap (iterator)
Definition: HashMap.java:65
Implementation of an unordered map based on a hash table.
Definition: HashMap.java:31
HashMap(int size)
create empty map
Definition: HashMap.java:135
static void main(String args[])
Definition: HashMap.java:308
Value insert(Key key, Value value)
insert key-value pair
Definition: HashMap.java:260
Entries entries()
get iterable instance for (HashMap<K,T>.Entry entry : map.entries()) { ... } @endiliteral
Definition: HashMap.java:207
HashMap()
create empty map
Definition: HashMap.java:143
Value find(Key key)
find value for key @endiliteral
Definition: HashMap.java:281
boolean is_empty()
is map empty?
Definition: HashMap.java:156
String toString()
Definition: HashMap.java:299
Value remove(Key key)
remove entry (equivalent to insert(key,null))
Definition: HashMap.java:273
boolean contains(Key key)
Is key contained in map?
Definition: HashMap.java:295
int size()
get current number of entries
Definition: HashMap.java:153
int getHashtableSize()
get current size of hash table (will be prime)
Definition: HashMap.java:148
double getLoadFactor()
get current load factor
Definition: HashMap.java:159
void reserve(int size)
Reserve buckets for expected size.
Definition: HashMap.java:175