4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 /* Compile time switches:
35 MULT - use a multiplicative hashing function.
36 DIV - use the remainder mod table size as a hashing function.
37 CHAINED - use a linked list to resolve collisions.
38 OPEN - use open addressing to resolve collisions.
39 BRENT - use Brent's modification to improve the OPEN algorithm.
40 SORTUP - CHAINED list is sorted in increasing order.
41 SORTDOWN - CHAINED list is sorted in decreasing order.
42 START - CHAINED list with entries appended at front.
43 DRIVER - compile in a main program to drive the tests.
44 DEBUG - compile some debugging printout statements.
45 USCR - user supplied comparison routine.
57 #define repeat for(;;)
58 #define until(A) if(A) break;
86 # define COMPARE(A, B) (* hcompar)((A), (B))
87 extern int (* hcompar
)();
89 # define COMPARE(A, B) strcmp((A), (B))
93 # define SHIFT ((bitsper * sizeof(int)) - m) /* Shift factor */
94 # define FACTOR 035761254233 /* Magic multiplication factor */
95 # define HASH hashm /* Multiplicative hash function */
96 # define HASH2 hash2m /* Secondary hash function */
97 static unsigned int bitsper
; /* Bits per byte */
98 static unsigned int hashm();
99 static unsigned int hash2m();
102 # define HASH hashd /* Division hashing routine */
103 # define HASH2(A) 1 /* Secondary hash function */
104 static unsigned int hashd();
109 FIND
, /* Find, if present */
110 ENTER
/* Find; enter if not present */
112 typedef char *POINTER
;
113 typedef struct entry
{ /* Hash table entry */
119 typedef struct node
{ /* Part of the linked list of entries */
123 typedef NODE
*TABELEM
;
124 static NODE
**table
; /* The address of the hash table */
125 static ENTRY
*build();
128 typedef ENTRY TABELEM
; /* What the table contains (TABle ELEMents) */
129 static TABELEM
*table
; /* The address of the hash table */
130 static unsigned int count
= 0; /* Number of entries in hash table */
134 static unsigned int length
; /* Size of the hash table */
135 static unsigned int m
; /* Log base 2 of length */
136 static unsigned int prcnt
; /* Number of probes this item */
141 static unsigned int crunch();
148 char line
[80]; /* Room for the input line */
149 int i
= 0; /* Data generator */
150 ENTRY
*res
; /* Result of hsearch */
151 ENTRY
*new; /* Test entry */
154 printf("Length = %u, m = %u\n", length
, m
);
156 fprintf(stderr
, "Out of core\n");
162 printf("Enter a probe: ");
163 until (EOF
== scanf("%s", line
));
165 printf("%s, ", line
);
166 printf("division: %d, ", hashd(line
));
167 printf("multiplication: %d\n", hashm(line
));
169 new = (ENTRY
*) malloc(sizeof(ENTRY
));
171 fprintf(stderr
, "Out of core \n");
175 new->key
= malloc((unsigned) strlen(line
) + 1);
176 if(new->key
== NULL
) {
177 fprintf(stderr
, "Out of core \n");
180 strcpy(new->key
, line
);
181 new->data
= malloc(sizeof(int));
182 if(new->data
== NULL
) {
183 fprintf(stderr
, "Out of core \n");
188 res
= hsearch(*new, ENTER
);
189 printf("The number of probes required was %d\n", prcnt
);
190 if(res
== (ENTRY
*) 0)
191 printf("Table is full\n");
194 printf("Key = %s, Value = %d\n", res
->key
, *res
->data
);
202 * Create a hash table no smaller than size
204 * size: Minimum size for hash table
209 unsigned int unsize
; /* Holds the shifted size */
214 unsize
= size
; /* +1 for empty table slot; -1 for ceiling */
215 length
= 1; /* Maximum entries in tabbe */
216 m
= 0; /* Log2 length */
223 table
= (TABELEM
*) calloc(length
, sizeof(TABELEM
));
224 return (table
!= NULL
);
228 hdestroy(void) /* Reset the module to its initial state */
230 free((POINTER
) table
);
237 /* Hash search of a fixed-capacity table. Open addressing used to
238 resolve collisions. Algorithm modified from Knuth, Volume 3,
239 section 6.4, algorithm D. Labels flag corresponding actions.
243 * Find or insert the item into the table
245 * item: Item to be inserted or found
246 * action: FIND or ENTER
249 hsearch(ENTRY item
, ACTION action
)
251 unsigned int i
; /* Insertion index */
252 unsigned int c
; /* Secondary probe displacement */
257 i
= HASH(item
.key
); /* Primary hash on key */
260 printf("hash = %o\n", i
);
264 if(table
[i
].key
== NULL
) /* Empty slot? */
266 else if(COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
270 c
= HASH2(item
.key
); /* No match => compute secondary hash */
273 printf("hash2 = %o\n", c
);
277 i
= (i
+ c
) % length
; /* Advance to next slot */
281 if(table
[i
].key
== NULL
) /* Empty slot? */
283 else if(COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
288 D6
: if(action
== FIND
) /* Insert if requested */
289 return((ENTRY
*) NULL
);
290 if(count
== (length
- 1)) /* Table full? */
294 /* Brent's variation of the open addressing algorithm. Do extra
295 work during insertion to speed retrieval. May require switching
296 of previously placed items. Adapted from Knuth, Volume 3, section
297 4.6 and Brent's article in CACM, volume 10, #2, February 1973.
300 { unsigned int p0
= HASH(item
.key
); /* First probe index */
301 unsigned int c0
= HASH2(item
.key
); /* Main branch increment */
302 unsigned int r
= prcnt
- 1; /* Current minimum distance */
303 unsigned int j
; /* Counts along main branch */
304 unsigned int k
; /* Counts along secondary branch */
305 unsigned int curj
; /* Current best main branch site */
306 unsigned int curpos
; /* Current best table index */
307 unsigned int pj
; /* Main branch indices */
308 unsigned int cj
; /* Secondary branch increment distance*/
309 unsigned int pjk
; /* Secondary branch probe indices */
312 for(j
= 0; j
< prcnt
; j
++) { /* Count along main branch */
313 pj
= (p0
+ j
* c0
) % length
; /* New main branch index */
314 cj
= HASH2(table
[pj
].key
); /* Secondary branch incr. */
315 for(k
=1; j
+k
<= r
; k
++) { /* Count on secondary branch*/
316 pjk
= (pj
+ k
* cj
) % length
; /* Secondary probe */
317 if(table
[pjk
].key
== NULL
) { /* Improvement found */
318 r
= j
+ k
; /* Decrement upper bound */
319 curj
= pj
; /* Save main probe index */
320 curpos
= pjk
; /* Save secondeary index */
324 if(r
!= prcnt
- 1) { /* If an improvement occurred */
325 table
[curpos
] = table
[curj
]; /* Old key to new site */
327 printf("Switch curpos = %o, curj = %o, oldi = %o\n",
335 count
++; /* Increment table occupancy count */
336 table
[i
] = item
; /* Save item */
337 return(&table
[i
]); /* Address of item is returned */
344 compare(POINTER a
, POINTER b
)
346 return (strcmp(a
, b
));
349 int (* hcompar
)() = compare
;
355 # define STRCMP(A, B) (COMPARE((A), (B)) > 0)
358 # define STRCMP(A, B) (COMPARE((A), (B)) < 0)
360 # define STRCMP(A, B) (COMPARE((A), (B)) != 0)
365 * Chained search with sorted lists
367 * item: Item to be inserted or found
368 * action: FIND or ENTER
371 hsearch(ENTRY item
, ACTION action
)
373 NODE
*p
; /* Searches through the linked list */
374 NODE
**q
; /* Where to store the pointer to a new NODE */
375 unsigned int i
; /* Result of hash */
376 int res
; /* Result of string comparison */
380 i
= HASH(item
.key
); /* Table[i] contains list head */
382 if(table
[i
] == (NODE
*)NULL
) { /* List has not yet been begun */
384 return((ENTRY
*) NULL
);
386 return(build(&table
[i
], (NODE
*) NULL
, item
));
388 else { /* List is not empty */
391 while(p
!= NULL
&& (res
= STRCMP(item
.key
, p
->item
.key
))) {
397 if(p
!= NULL
&& res
== 0) /* Item has been found */
399 else { /* Item is not yet on list */
401 return((ENTRY
*) NULL
);
404 return(build(&table
[i
], table
[i
], item
));
406 return(build(q
, p
, item
));
413 * last: Where to store in last list item
414 * next: Link to next list item
415 * item: Item to be kept in node
418 build(NODE
**last
, NODE
*next
, ENTRY item
)
420 NODE
*p
= (NODE
*) malloc(sizeof(NODE
));
435 * Division hashing scheme
437 * key: Key to be hashed
442 return (crunch(key
) % length
);
447 * NOTE: The following algorithm only works on machines where
448 * the results of multiplying two integers is the least
449 * significant part of the double word integer required to hold
450 * the result. It is adapted from Knuth, Volume 3, section 6.4.
454 * Multiplication hashing scheme
456 * key: Key to be hashed
461 static int first
= TRUE
; /* TRUE on the first call only */
463 if(first
) { /* Compute the number of bits in a byte */
464 unsigned char c
= UCHAR_MAX
; /* A byte full of 1's */
466 while(c
) { /* Shift until no more 1's */
468 bitsper
++; /* Count number of shifts */
472 return ((int) (((unsigned) (crunch(key
) * FACTOR
)) >> SHIFT
));
476 * Secondary hashing, for use with multiplicitive hashing scheme.
477 * Adapted from Knuth, Volume 3, section 6.4.
481 * Secondary hashing routine
483 * key: String to be hashed
488 return ((int) (((unsigned) ((crunch(key
) * FACTOR
) << m
) >> SHIFT
) | 1));
493 /* Convert multicharacter key to unsigned int */
497 unsigned int sum
= 0; /* Results */
498 int s
; /* Length of the key */
500 for(s
= 0; *key
; s
++) /* Simply add up the bytes */
508 hdump() /* Dumps loc, data, probe count, key */
510 unsigned int i
; /* Counts table slots */
512 unsigned int sum
= 0; /* Counts probes */
515 NODE
*a
; /* Current Node on list */
519 for(i
= 0; i
< length
; i
++)
521 if(table
[i
].key
== NULL
)
522 printf("%o.\t-,\t-,\t(NULL)\n", i
);
524 unsigned int oldpr
= prcnt
; /* Save current probe count */
525 hsearch(table
[i
], FIND
);
527 printf("%o.\t%d,\t%d,\t%s\n", i
,
528 *table
[i
].data
, prcnt
, table
[i
].key
);
531 printf("Total probes = %d\n", sum
);
535 printf("%o.\t-,\t-,\t(NULL)\n", i
);
538 for(a
= table
[i
]; a
!= NULL
; a
= a
->next
)
539 printf("\t%d,\t%#0.4x,\t%s\n",
540 *a
->item
.data
, a
, a
->item
.key
);