实现一个简单的哈希表。
- /*
- * hashtab.h -
- * A hash table (hashtab) maintains associations between
- * key values and datum values. The type of the key values
- * and the type of the datum values is arbitrary. The
- * functions for hash computation and key comparison are
- * provided by the creator of the table.
- *
- * Author : jta, 2008, 6
- */
- #ifndef _HASHTAB_H_
- #define _HASHTAB_H_
- #ifdef __cplusplus
- extern "C" {
- #endif
- #define HASHTAB_MAX_NODES 0xffffffff
- typedef unsigned long u32;
- struct hashtab_node {
- void *key;
- void *datum;
- struct hashtab_node *next;
- };
- struct hashtab {
- struct hashtab_node **htable; /* hash table */
- u32 size; /* number of slots in hash table */
- u32 nel; /* number of elements in hash table */
- u32 (*hash_value)(struct hashtab *h, void *key);
- /* hash function */
- int (*keycmp)(struct hashtab *h, void *key1, void *key2);
- /* key comparison function */
- };
- struct hashtab_info {
- u32 slots_used;
- u32 max_chain_len;
- };
- /*
- * Creates a new hash table with the specified characteristics.
- *
- * Returns NULL if insufficent space is available or
- * the new hash table otherwise.
- */
- struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
- int (*keycmp)(struct hashtab *h, void *key1, void *key2),
- u32 size);
- /*
- * Inserts the specified (key, datum) pair into the specified hash table.
- *
- * Returns -ENOMEM on memory allocation error,
- * -EEXIST if there is already an entry with the same key,
- * -EINVAL for general errors or
- * 0 otherwise.
- */
- #define hashtab_add hashtab_insert
- int hashtab_insert(struct hashtab *h, void *k, void *d);
- /*
- * Searches for the entry with the specified key in the hash table.
- *
- * Returns NULL if no entry has the specified key or
- * the datum of the entry otherwise.
- */
- void *hashtab_search(struct hashtab *h, void *k);
- /*
- * Destroys the specified hash table.
- */
- void hashtab_destroy(struct hashtab *h);
- /*
- * Applies the specified apply function to (key,datum,args)
- * for each entry in the specified hash table.
- *
- * The order in which the function is applied to the entries
- * is dependent upon the internal structure of the hash table.
- *
- * If apply returns a non-zero status, then hashtab_map will cease
- * iterating through the hash table and will propagate the error
- * return to its caller.
- */
- int hashtab_map(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
- void *args);
- /* Fill info with some hash table statistics */
- void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
- #ifdef __cplusplus
- }
- #endif
- #endif /* _HASHTAB_H_ */
- /*
- * hashtab.c - Implementation of the hash table.
- *
- * Author : jta, 2008, 6
- */
- #include <string.h>
- #include <malloc.h>
- #include "hashtab.h"
- u32 hashfun( struct hashtab * h , void* key ) ;
- int keycmp(struct hashtab *h, void *key1, void *key2);
- struct hashtab *hashtab_create(u32 (*value)(struct hashtab *h, void *key),
- int (*cmp)(struct hashtab *h, void *key1, void *key2),
- u32 size)
- {
- struct hashtab *p;
- u32 i;
- p = malloc(sizeof(*p));
- if (p == NULL)
- return p;
- memset(p,0,sizeof(*p));
- p->size = size;
- p->nel = 0;
- p->hash_value = value? value : hashfun;
- p->keycmp = cmp ? cmp : keycmp;
- p->htable = malloc(sizeof(*(p->htable)) * size);
- if (p->htable == NULL) {
- free(p);
- return NULL;
- }
- for (i = 0; i < size; i++)
- p->htable[i] = NULL;
- return p;
- }
- int hashtab_insert(struct hashtab *h, void *key, void *datum)
- {
- u32 hvalue;
- struct hashtab_node *prev, *cur, *newnode;
- if (!h || h->nel == HASHTAB_MAX_NODES)
- return -1;
- hvalue = h->hash_value(h, key);
- prev = NULL;
- cur = h->htable[hvalue];
- while (cur && h->keycmp(h, key, cur->key) > 0) {
- prev = cur;
- cur = cur->next;
- }
- if (cur && (h->keycmp(h, key, cur->key) == 0))
- return -1;
- newnode = malloc(sizeof(*newnode));
- memset(newnode, 0, sizeof(*newnode));
- if (newnode == NULL)
- return -1;
- newnode->key = key;
- newnode->datum = datum;
- if (prev) {
- newnode->next = prev->next;
- prev->next = newnode;
- } else {
- newnode->next = h->htable[hvalue];
- h->htable[hvalue] = newnode;
- }
- h->nel++;
- return 0;
- }
- void *hashtab_search(struct hashtab *h, void *key)
- {
- u32 hvalue;
- struct hashtab_node *cur;
- if (!h)
- return NULL;
- hvalue = h->hash_value(h, key);
- cur = h->htable[hvalue];
- while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
- cur = cur->next;
- if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
- return NULL;
- return cur->datum;
- }
- void hashtab_destroy(struct hashtab *h)
- {
- u32 i;
- struct hashtab_node *cur, *temp;
- if (!h)
- return;
- for (i = 0; i < h->size; i++) {
- cur = h->htable[i];
- while (cur != NULL) {
- temp = cur;
- cur = cur->next;
- free(temp);
- }
- h->htable[i] = NULL;
- }
- free(h->htable);
- h->htable = NULL;
- free(h);
- }
- int hashtab_map(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
- void *args)
- {
- u32 i;
- int ret;
- struct hashtab_node *cur;
- if (!h)
- return 0;
- for (i = 0; i < h->size; i++) {
- cur = h->htable[i];
- while (cur != NULL) {
- ret = apply(cur->key, cur->datum, args);
- if (ret)
- return ret;
- cur = cur->next;
- }
- }
- return 0;
- }
- void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
- {
- u32 i, chain_len, slots_used, max_chain_len;
- struct hashtab_node *cur;
- slots_used = 0;
- max_chain_len = 0;
- for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
- cur = h->htable[i];
- if (cur) {
- slots_used++;
- chain_len = 0;
- while (cur) {
- chain_len++;
- cur = cur->next;
- }
- if (chain_len > max_chain_len)
- max_chain_len = chain_len;
- }
- }
- info->slots_used = slots_used;
- info->max_chain_len = max_chain_len;
- }
- /**
- * Default hash function
- */
- u32 hashfun( struct hashtab * h , void* key )
- {
- int* pi = (int *)key ;
- return *pi%10 ;
- }
- int keycmp(struct hashtab *h, void *key1, void *key2)
- {
- int* pi1 = (int *)key1 ;
- int* pi2 = (int *)key2 ;
- return *pi1 - *pi2;
- }
- #ifdef _DEBUG_HASHTAB_
- int main()
- {
- struct hashtab *hash ;
- u32 size = 10;
- hash = hashtab_create(hashfun, keycmp, size);
- int x = (hash->hash_value)( hash, (void *)&size );
- int tk = 21;
- char cd[5] = "xx";
- hashtab_insert(hash, (void*)&tk, (void*)cd);
- char* cp = (char*)hashtab_search(hash, (void*)&tk);
- printf("%s",cp);
- return 0;
- }
- #endif