Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

hash.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  * DESCRIPTION:
00003  *   A simple hash table implementation for strings, contributed by John Stone,
00004  *   derived from his ray tracer code.
00005  ***************************************************************************/
00006 
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include "hash.h"
00011 
00012 #define HASH_LIMIT 0.5
00013 
00014 /*
00015  *  Local types
00016  */
00017 typedef struct hash_node_t
00018 {
00019   void  *data;                        /* data in hash node */
00020   char * key;                         /* key for hash lookup */
00021   struct hash_node_t *next;           /* next node in hash chain */
00022 } hash_node_t;
00023 
00024 /*
00025  *  hash() - Hash function returns a hash number for a given key.
00026  *
00027  *  tptr: Pointer to a hash table
00028  *  key: The key to create a hash number for
00029  */
00030 static int
00031 hash (const hash_t *tptr, const char *key)
00032 {
00033   int i = 0;
00034   int hashvalue;
00035 
00036   while (*key != '\0')
00037     i = (i<<3) + (*key++ - '0');
00038 
00039   hashvalue = (((i*1103515249) >> tptr->downshift) & tptr->mask);
00040   if (hashvalue < 0) {
00041     hashvalue = 0;
00042   }
00043 
00044   return hashvalue;
00045 }
00046 
00047 /*
00048  *  rebuild_table() - Create new hash table when old one fills up.
00049  *
00050  *  tptr: Pointer to a hash table
00051  */
00052 static void
00053 rebuild_table (hash_t *tptr)
00054 {
00055   hash_node_t **old_bucket;
00056   hash_node_t *old_hash;
00057   hash_node_t *tmp;
00058   
00059   int old_size;
00060   int h;
00061   int i;
00062 
00063   old_bucket = tptr->bucket;
00064   old_size   = tptr->size;
00065 
00066   /* create a new table and rehash old buckets */
00067   hash_init (tptr, old_size << 1);
00068   
00069   for (i=0; i<old_size; i++)
00070   {
00071     old_hash = old_bucket[i];
00072     
00073     while (old_hash)
00074     {
00075       tmp       = old_hash;
00076       old_hash  = old_hash->next;
00077       h         = hash (tptr, tmp->key);
00078       tmp->next = tptr->bucket[h];
00079       tptr->bucket[h] = tmp;
00080       tptr->entries++;
00081     } /* while */
00082   } /* for */
00083 
00084   /* free memory used by old table */
00085   free (old_bucket);
00086 
00087   return;
00088 }
00089 
00090 /*
00091  *  hash_init() - Initialize a new hash table.
00092  *
00093  *  tptr: Pointer to the hash table to initialize
00094  *  buckets: The number of initial buckets to create
00095  */
00096 void
00097 hash_init (hash_t *tptr, int buckets)
00098 {
00099 
00100   /* make sure we allocate something */
00101   if (buckets == 0)
00102     buckets = 16;
00103 
00104   /* initialize the table */
00105   tptr->entries   = 0;
00106   tptr->size      = 2;
00107   tptr->mask      = 1;
00108   tptr->downshift = 29;
00109 
00110   /* ensure buckets is a power of 2 */
00111   while (tptr->size < buckets)
00112   {
00113     tptr->size <<= 1;
00114     tptr->mask   = (tptr->mask << 1) + 1;
00115     tptr->downshift--;
00116   } /* while */
00117 
00118   /* allocate memory for table */
00119   tptr->bucket = (hash_node_t **) calloc (tptr->size, sizeof (hash_node_t *));
00120 
00121   return;
00122 }
00123 
00124 /*
00125  *  hash_lookup() - Lookup an entry in the hash table and return a pointer to
00126  *    it or NULL if it wasn't found.
00127  *
00128  *  tptr: Pointer to the hash table
00129  *  key: The key to lookup
00130  */
00131 void *
00132 hash_lookup(const hash_t *tptr, const char *key)
00133 {
00134   int h;
00135   hash_node_t *node;
00136 
00137 
00138   /* find the entry in the hash table */
00139   h = hash (tptr, key);
00140   for (node = tptr->bucket[h]; node != NULL; node = node->next)
00141   {
00142     if (!strcmp (node->key, key))
00143       break;
00144   }
00145 
00146   /* return the entry if it exists, or NULL */
00147   return (node ? node->data : NULL);
00148 }
00149 
00150 /*
00151  *  hash_insert() - Insert an entry into the hash table.  If the entry already
00152  *  exists return a pointer to it, otherwise return NULL.
00153  *
00154  *  tptr: A pointer to the hash table
00155  *  key: The key to insert into the hash table
00156  *  data: A pointer to the data to insert into the hash table
00157  */
00158 void *
00159 hash_insert (hash_t *tptr, const char *key, void *data)
00160 {
00161   void        *tmp;
00162   hash_node_t *node;
00163   int          h;
00164 
00165 
00166   /* check to see if the entry exists */
00167   if ((tmp = hash_lookup (tptr, key)) != NULL)
00168     return (tmp);
00169 
00170   /* expand the table if needed */
00171   while (tptr->entries >= HASH_LIMIT * tptr->size)
00172     rebuild_table (tptr);
00173 
00174   /* insert the new entry */
00175   h    = hash (tptr, key);
00176   node = (struct hash_node_t *) malloc (sizeof (hash_node_t));
00177   node->data      = data;
00178   node->key       = strdup (key);
00179   node->next      = tptr->bucket[h];
00180   tptr->bucket[h] = node;
00181   tptr->entries++;
00182 
00183   return NULL;
00184 }
00185 
00186 /*
00187  *  hash_delete() - Remove an entry from a hash table and return a pointer
00188  *  to its data or NULL if it wasn't found.
00189  *
00190  *  tptr: A pointer to the hash table
00191  *  key: The key to remove from the hash table
00192  */
00193 void *
00194 hash_delete(hash_t *tptr, const char *key)
00195 {
00196   hash_node_t *node;
00197   hash_node_t *last;
00198   void        *data;
00199   int          h;
00200 
00201   /* find the node to remove */
00202   h = hash (tptr, key);
00203   for (node = tptr->bucket[h]; node; node = node->next)
00204   {
00205     if (!strcmp (node->key, key))
00206       break;
00207   }
00208 
00209   /* Didn't find anything, return HASH_FAIL */
00210   if (node == NULL)
00211     return NULL;
00212 
00213   /* if node is at head of bucket, we have it easy */
00214   if (node == tptr->bucket[h])
00215     tptr->bucket[h] = node->next;
00216   else
00217   {
00218     /* find the node before the node we want to remove */
00219     for (last = tptr->bucket[h]; last && last->next; last = last->next)
00220     {
00221       if (last->next == node)
00222         break;
00223     }
00224     last->next = node->next;
00225   }
00226 
00227   /* free memory and return the data */
00228   data = node->data;
00229   free (node->key);
00230   free (node);
00231 
00232   return (data);
00233 }
00234 
00235 
00236 
00237 /*
00238  * hash_destroy() - Delete the entire table, and all remaining entries.
00239  *
00240  */
00241 void
00242 hash_destroy (hash_t *tptr, void (*free_data)(void *))
00243 {
00244   hash_node_t *node;
00245   hash_node_t *last;
00246   int          i;
00247 
00248   for (i = 0; i < tptr->size; i++)
00249   {
00250     node = tptr->bucket[i];
00251     while (node != NULL)
00252     {
00253       last = node;
00254       node = node->next;
00255       free_data (last->data);
00256       free (last->key);
00257       free (last);
00258     }
00259   }
00260 
00261   /* free the entire array of buckets */
00262   if (tptr->bucket != NULL)
00263   {
00264     free (tptr->bucket);
00265     memset (tptr, 0, sizeof (hash_t));
00266   }
00267 }
00268 
00269 /*
00270  *  alos() - Find the average length of search.
00271  *
00272  *  tptr: Pointer to a hash table
00273  */
00274 static float alos(hash_t *tptr) {
00275   int i,j;
00276   float alos=0;
00277   hash_node_t *node;
00278 
00279 
00280   for (i=0; i<tptr->size; i++) {
00281     for (node=tptr->bucket[i], j=0; node!=NULL; node=node->next, j++);
00282     if (j)
00283       alos+=((j*(j+1))>>1);
00284   } /* for */
00285 
00286   return(tptr->entries ? alos/tptr->entries : 0);
00287 }
00288 
00289 
00290 /*
00291  *  hash_stats() - Return a string with stats about a hash table.
00292  *
00293  *  tptr: A pointer to the hash table
00294  */
00295 char * hash_stats(hash_t *tptr) {
00296   static char buf[1024];
00297 
00298   sprintf(buf, "%u slots, %u entries, and %1.2f ALOS",
00299     (int)tptr->size, (int)tptr->entries, alos(tptr));
00300 
00301   return(buf);
00302 }
00303 

Generated on Sun Jun 13 20:50:13 2004 for libgnn Gradient Retropropagation Machine Library by doxygen1.2.18