hsearch_r(), hcreate_r() y hdestroy_r() son funciones POSIX para el manejo de hashtables. No son las más intuitivas, ni tampoco las más portables, pero el hecho de que vengan con cualquier sistema GNU y no tengas que instalarlas las hace muy cómodas.
Dado que trabajar con ellas es poco práctico he creado unas macros que facilitan su uso y hacen el código más legible. Son las siguientes:
#define _GNU_SOURCE #include <search.h> #define HASHTABLE_CREATE(name, sz) \ struct hsearch_data *name = calloc(sz, sizeof(struct htsearch_data*)); \ hcreate_r(sz, name); #define HASHTABLE_DESTROY(name) hdestroy_r(name) #define HASHTABLE_SET(name, strkey, value) \ { \ ENTRY e, *r; \ e.key = strkey; \ if(hsearch_r(e, FIND, &r, name)) \ { \ r->data = (void*) (value); \ } \ else \ { \ e.data = (void*) (value); \ hsearch_r(e, ENTER, &r, name); \ } \ } #define HASHTABLE_GET(name, strkey, value) \ { \ ENTRY e, *r; \ e.key = strkey; \ if(hsearch_r(e, FIND, &r, name)) \ { \ value=(int)r->data; \ } \ else \ { \ value=(int)0; \ } \ }Pegando este código en el programa, se pueden usar fácilmente hashtables, como se muestra en el ejemplo:
HASHTABLE_CREATE(ht, 100); HASHTABLE_SET(ht, "e1", 1); HASHTABLE_SET(ht, "e2", 2); HASHTABLE_SET(ht, "e3", 3); HASHTABLE_SET(ht, "e4", 4); HASHTABLE_SET(ht, "e5", 5); int i; HASHTABLE_GET(ht, "e1", i); printf("val: %d\n", i); HASHTABLE_GET(ht, "e2", i); printf("val: %d\n", i); HASHTABLE_GET(ht, "e3", i); printf("val: %d\n", i); HASHTABLE_GET(ht, "e4", i); printf("val: %d\n", i); HASHTABLE_DESTROY(ht);
Como se ve, el ejemplo es muy sencillo. Primero creamos una estructura con espacio para 100 elementos (caben más, pero habrá colisiones y no será óptimo). Después añadimos elementos, y posteriormente los consultamos. Finalmente, eliminamos la estructura.
A tener en cuenta que HASHTABLE_GET almacena el resultado en "i", lo cual puede confundir un poco al leer el código.
Las macros están hechas para trabajar con valores enteros, pero son fácilmente modificables.