AuD
Lecture 'Algorithmen und Datenstrukturen' (code examples)
HashtableExample.java
Go to the documentation of this file.
1package aud.example.hash;
2
3import java.io.File;
4import java.util.Scanner;
5
7import aud.util.SVGViewer;
8
23public class HashtableExample {
24
29 static public class HashString extends HashFunction<String> {
30 long m_ = 2019773507l; // Integer range18014398509481951l;
31
32 public HashString() {}
33 public HashString(long m) { this(); m_=m; }
34
35 @Override public long hash(String s) {
36 long h=0;
37 for (byte b : s.getBytes()) {
38 h =(h*0x100+(b+0x80));
39 h%=m_;
40 }
41 //System.err.println(s+" -> "+h);
42 return h;
43 }
44 @Override public String toString() {
45 return "HashString[m="+m_+"]";
46 }
47 }
48
52 static public class IdentityHash extends HashFunction<Integer> {
53 @Override public long hash(Integer k) { return k; }
54 @Override public String toString() {
55 return "Identity";
56 }
57 }
58
63 static public class UniversalHash extends HashFunction<Integer> {
64 long a_ = 7177;
65 long b_ = 3179303;
66 long p_ = 18014398509481951l;
67
68 public UniversalHash() {}
69 public UniversalHash(long a,long b,long p) {
70 this();
71 assert(0<a && a<p && 0<=b && b<p);
72 a_=a; b_=b; p_=p;
73 }
74
75 @Override public long hash(Integer k) {
76 return (a_*(k>=0 ? k : -k)+b_) % p_;
77 }
78 @Override public String toString() {
79 return "UniversalHash[a="+a_+", b="+b_+", p="+p_+"]";
80 }
81 }
82
84 public class LinearProbing<T> extends CollisionHandler<T> {
85 int b_ = 1;
86 public LinearProbing() {}
87 public LinearProbing(int b) {
88 this();
89 assert(b>0);
90 b_=b;
91 }
92
93 @Override public long
94 newHash(SimpleHashtable<T> table,T key,long h,int count) {
95 return h+count*b_;
96 }
97
98 @Override public String toString() {
99 return "LinearProbing[b="+b_+"]";
100 }
101 }
102
104 public class QuadraticProbing<T> extends CollisionHandler<T> {
105 int b_ = 1;
106 int c_ = 1;
108 public QuadraticProbing(int b,int c) {
109 this();
110 assert(b>=0 && c>0);
111 b_=b;
112 c_=c;
113 }
114
115 @Override public long
116 newHash(SimpleHashtable<T> table,T key,long h,int count) {
117 return h + count*b_ + (count*count)*c_;
118 }
119
120 @Override public String toString() {
121 return "QuadraticProbing[b="+b_+", c="+c_+"]";
122 }
123 }
124
126 public class DoubleHashing<T> extends CollisionHandler<T> {
127 HashFunction<T> h2_ = null;
128
129 public DoubleHashing(HashFunction<T> h2) { h2_=h2; }
130
131 @Override public long
132 newHash(SimpleHashtable<T> table,T key,long h,int count) {
133 long h2=h2_.hash(key);
134 return h+count*(h2!=0 ? h2 : 18014398509481951l);
135 }
136
137 @Override public String toString() {
138 return "DoubleHahsing[h2="+h2_+"]";
139 }
140 }
141
142 //
143 // test framework
144 //
145
150 class Key {
151 final HashString hashstring = new HashString();
152
153 public long intValue;
154 String s = null;
155
157 public Key(Integer i) { intValue=i; }
159 public Key(String s) { intValue=hashstring.hash(s); this.s=s; }
160
161 public boolean equals(Key other) {
162 return s==null ?
163 (intValue==other.intValue) :
164 (s.compareTo(other.s)==0);
165 }
166
167 @Override public String toString() {
168 return s!=null ? s : (""+intValue);
169 }
170 }
171
173 class HashKey extends HashFunction<Key> {
174 HashFunction<Integer> ihash;
175 HashKey(HashFunction<Integer> hash) { this.ihash=hash; }
176 @Override public long hash(Key k) { return ihash.hash((int) k.intValue); }
177
178 @Override public String toString() {
179 return ihash.toString();
180 }
181 }
182
184 SimpleHashtable<Key> hashtable=null;
185
187 HashFunction<Key> hashfunction=new HashKey(new IdentityHash());
188
190 CollisionHandler<Key> collisionhandler=null;
191
193 boolean readIntegers=true;
194
196 int timestep = 1;
197
199 int time=0;
200
202 int verbose = 0;
203
205 static void usage() {
206 System.err.println(
207 "java HashtableExample [-m M] [-s|--string] [--timestep T]\n"+
208 " [-v | --verbose LEVEL]\n"+
209 " [-u] [--universal A B P]\n"+
210 " [-L] [--linear B]\n"+
211 " [-Q] [--quadratic B C]\n"+
212 " [-S] [--separate]\n"+
213 " [-D] [--double]\n[-h] [--help]\n\n"+
214 " The short form switches ('-' except '-m') don't take parameters,\n"+
215 " the long forms '--' require all listed parameters. (See methods\n"+
216 " for a description of parameters.)\n\n"+
217 " -s | --string forces input of strings otherwise integers are\n"+
218 " expected!\n"+
219 " --timestep set timestep for recording history\n"+
220 " -v | --verbose print additonal information\n"+
221 " The default hash function is modulo table size M (default M=11).\n"+
222 " -u | --universal select the universal has function\n\n"+
223 " -L,-Q,-S select linear probing, quadratic probing, or separate\n"+
224 " chaining (default)\n"+
225 " -D selects double hashing, any subsequent -u | --universal modifies\n"+
226 " the secondary hash function, which should be specified\n"+
227 " differently from the primal hash function! (No checks!)\n\n"+
228 " -h | --help displays this message\n\n"+
229 "The program reads from standard input and inserts integers/words to\n"+
230 "into the hash table.\n"+
231 "The following \"words\" have a special meaning:\n"+
232 " '.' quits,\n" +
233 " '?' prints the contents of the hash table to standard output\n"+
234 " '!' visualizes the history of the hash table in a new window\n\n"
235 );
236 System.exit(-1);
237 }
238
240 public HashtableExample(String args[]) {
241 int m=11;
242
243 HashFunction<Integer> h2=new IdentityHash();
244 boolean haveDoubleHashing=false;
245
246 for (int i=0;i<args.length;++i) {
247 if (args[i].compareTo("-m")==0)
248 m=Integer.parseInt(args[++i]);
249 else if (args[i].compareTo("--timestep")==0)
250 timestep=Integer.parseInt(args[++i]);
251 else if (args[i].compareTo("-v")==0)
252 ++verbose;
253 else if (args[i].compareTo("--verbose")==0)
254 verbose=Integer.parseInt(args[++i]);
255 else if (args[i].compareTo("--string")==0 || args[i].compareTo("-s")==0)
256 readIntegers=false;
257 else if (args[i].compareTo("--help")==0 || args[i].compareTo("-h")==0)
258 usage();
259 else if (args[i].compareTo("-u")==0)
260 hashfunction=new HashKey(new UniversalHash());
261 else if (args[i].compareTo("--universal")==0) {
262 HashFunction<Integer> h=
263 new UniversalHash(
264 Integer.parseInt(args[++i]), // a
265 Integer.parseInt(args[++i]), // b
266 Integer.parseInt(args[++i]) // p
267 );
268 if (haveDoubleHashing)
269 h2=h;
270 else
271 hashfunction=new HashKey(h);
272 }
273 else if (args[i].compareTo("--separate")==0 || args[i].compareTo("-S")==0)
274 collisionhandler=null;
275 else if (args[i].compareTo("-L")==0)
276 collisionhandler=new LinearProbing<Key>();
277 else if (args[i].compareTo("--linear")==0)
278 collisionhandler=new LinearProbing<Key>(Integer.parseInt(args[++i]));
279 else if (args[i].compareTo("-Q")==0)
280 collisionhandler=new QuadraticProbing<Key>();
281 else if (args[i].compareTo("--quadratic")==0)
282 collisionhandler=new QuadraticProbing<Key>
283 (Integer.parseInt(args[++i]),Integer.parseInt(args[++i]));
284 else if (args[i].compareTo("--double")==0 || args[i].compareTo("-D")==0) {
285 haveDoubleHashing=true;
286 collisionhandler=null;
287 }
288 else
289 usage();
290 }
291
292 if (haveDoubleHashing)
293 collisionhandler=new DoubleHashing<Key>(new HashKey(h2));
294
295
296 System.err.println("> hash table with m="+m);
297 System.err.println("> hash function="+hashfunction);
298 System.err.println("> collision handling="+
299 (collisionhandler==null ?
300 "separate chaining" : collisionhandler.toString()
301 ));
302 if (readIntegers)
303 System.err.println("> reading integers...\n");
304 else
305 System.err.println("> reading strings (HashString)...\n");
306
307 hashtable=new SimpleHashtable<Key>(m,hashfunction,collisionhandler);
308 hashtable.verbose=(verbose>0);
309 }
310
312 public void start() {
313 SVGViewer viewer=null;
314 time=0;
315 hashtable.beginRecording();
316
317 Scanner s=new Scanner(System.in);
318 s.useDelimiter("\\s+");
319
320 while (s.hasNext()) {
321 String key=s.next();
322 if (key.startsWith("."))
323 break;
324 else if (key.startsWith("?")) {
325 if (key.startsWith("?svg:")) {
326 hashtable.history_.renderSpySVG(
327 new File(key.substring(5)+".svg"),new ColormapCount());
328 }
329 else if (key.startsWith("?tikz"))
330 System.out.println(hashtable
331 .history_.spyTikZ(true,new ColormapCount()));
332 else
333 System.out.println(hashtable);
334 }
335 else if (key.startsWith("!")) {
336 if (viewer!=null)
337 viewer.close();
338 viewer=hashtable.showHistory();
339 }
340 else {
341 Key k=readIntegers ? new Key(Integer.parseInt(key)) : new Key(key);
342 if ((time++)%timestep==0)
343 hashtable.nextTimeStep();
344 hashtable.insert(k);
345 }
346 }
347
348 if (viewer!=null)
349 viewer.close();
350 viewer=hashtable.showHistory();
351 // TODO reuse viewer instance (write to same tempfile)
352 }
353 // TODO: catch exceptions (cycles while probing)
354
356 public static void main(String args[]) {
357 new HashtableExample(args).start();
358 }
359}
Collision handling strategy in SimpleHashtable.
interface for a hash function
Collision handling by double hashing using h2
long newHash(SimpleHashtable< T > table, T key, long h, int count)
Handle collision by computing a new hash value.
Collision handling by linear probing h(x,i)=h(x)+i*b
long newHash(SimpleHashtable< T > table, T key, long h, int count)
Handle collision by computing a new hash value.
Collision handling by quadratic probing h(x,i)=h(x)+i*b+i*i*c
long newHash(SimpleHashtable< T > table, T key, long h, int count)
Handle collision by computing a new hash value.
Simple framework for experiments with hash tables.
Base class for simple hash tables (mainly for demonstration).
color map for (small) positive integer counts
Simple SVG viewer based on Batik's SVGCanvas.
Definition: SVGViewer.java:33
utilities (not related to AuD lecture)
Definition: Colormap.java:1
AuD lecture: Data structures, algorithms, examples.
Definition: A234Tree.java:1