Hashtable(完整实现)

请支持原创作者, 转载请说明出处! 

#ifndef _HASHTABLE_H
#define _HASHTABLE_H

struct hashtable;

struct hashtable*  hashtable_create(unsigned long size, unsigned long(*hash_func)(const void *key),
                                    int(*test_func)(const void *key1, const void *key2));

struct hashtable*  make_string_hashtable(unsigned long size);

int hashtable_put(struct hashtable *ht, const void *key, void *value);

void* hashtable_get(struct hashtable *ht, const void *key);

int hashtable_remove(struct hashtable *ht, const void *key);

int hashtable_contains(struct hashtable *ht, const void *key);

int hashtable_set(struct hashtable *ht, const void *key, void *newvalue);

unsigned long hashtable_count(struct hashtable *ht);

void hashtable_map(struct hashtable *ht, int(*mapfunc)(void*, void*, void*), void*);

void hashtable_clear(struct hashtable *ht);

void hashtable_close(struct hashtable *ht);

#endif

 

 

 

#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include "hashtable.h"

/* Hashtable MAX fullness, you can amend it, but it may best, i think. */
#define HASH_MAX_FULLNESS 0.75

#define HASH_RESIZE_FACTOR 2

#define HASH_POSITION(key, hash_func, size) ((hash_func)(key) % size)

/* Because linuxget hashtable allow 0/NULL key. So we use -1 to point
   empty hash mapping. */
#define INVALID_PTR ((void*) ~(unsigned long)0)

#define INVALID_PTR_BYTE 0xff

#define NON_EMPTY(mapping) ((mapping)->key != INVALID_PTR)


typedef unsigned long (*hash_func_t)(const void *key);
typedef int (*test_func_t)(const void *key1, const void *key2);

struct hash_mapping {
   void  *key;
   void  *value;
};

struct hashtable {
   hash_func_t          hash_func;        /* Hash function pointer. */
   test_func_t          test_func;        /* Hash key compare function pointer. */
   struct hash_mapping *mappings;         /* Hashtable data entries. */
   unsigned long        count;            /* Current hashtable not NULL entry count. */
   unsigned long        size;             /* Current hashtable size. */
   int                  prime_offset;     /* The offset for prime size. */
   unsigned long        resize_threshold; /* Hashtable resize threshold, when size more than this
                                             , grow it. */
};

/***********************************************************************
 * Not link functions.
 ***********************************************************************/

/* Prime the hashtable size. */
static unsigned long prime_size(unsigned long size, int *prime_offset) {
   static const unsigned long primes[] = {
      13, 19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031,
      1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783,
      19219, 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941,
      204047, 265271, 344857, 448321, 582821, 757693, 985003, 1280519,
      1664681, 2164111, 2813353, 3657361, 4754591, 6180989, 8035301,
      10445899, 13579681, 17653589, 22949669, 29834603, 38784989,
      50420551, 65546729, 85210757, 110774011, 144006217, 187208107,
      243370577, 316381771, 411296309, 534685237, 695090819, 903618083,
      1174703521, 1527114613, 1837299131, 2147483647};
 
   int i;
   for(i = *prime_offset; i < sizeof(primes) / sizeof(unsigned long); ++i) {
      if(primes[i] >= size) {
         *prime_offset = i + 1;
          return primes[i];
      }
   }

   abort();    /* Hash table range out. */
}

static int grow_hashtable(struct hashtable *ht) {
   if(!ht)
      return 0;
 
   unsigned long newsize = prime_size(ht->size * HASH_RESIZE_FACTOR, &ht->prime_offset);
   ht->mappings = realloc(ht->mappings, newsize * sizeof(struct hash_mapping));
   memset(ht->mappings + ht->size, INVALID_PTR_BYTE,
                                  (newsize - ht->size) * sizeof(struct hash_mapping));
   ht->size = newsize;
   ht->resize_threshold = newsize * HASH_MAX_FULLNESS;
 
   return 1;
}

/* Hash function. If not give customer hash function, use it.
   This implementation is the Robert Jenkins' 32 bit Mix Function,
   with a simple adaptation for 64-bit values.*/
static unsigned long hash_pointer(const void *key) {
   unsigned long hashval = (unsigned long)key;
 
   hashval += (hashval << 12);
   hashval ^= (hashval >> 22);
   hashval += (hashval << 4);
   hashval ^= (hashval >> 9);
   hashval += (hashval << 10);
   hashval ^= (hashval >> 2);
   hashval += (hashval << 7);
   hashval ^= (hashval >> 12);
   #if ULONG_MAX > 4294967295
   hashval += (hashval << 44);
   hashval ^= (hashval >> 54);
   hashval += (hashval << 36);
   hashval ^= (hashval >> 41);
   hashval += (hashval << 42);
   hashval ^= (hashval >> 34);
   hashval += (hashval << 39);
   hashval ^= (hashval >> 44);
   #endif
 
   return hashval;
}

/* Hash function. Only use in string hash table. This is a
   31 bit hash function.  Taken from Gnome's glib,
   modified to use standard C types.*/
static unsigned long hash_string(const void *key) {
   const char *p = key;
   unsigned int h = *p;
 
   if (h)
     for (p += 1; *p != '/0'; p++)
        h = (h << 5) - h + *p;
 
   return h;
}
 
/* Hash key compare function. If not give customer compare function,
   use it. */
static int cmp_pointer(const void *key1, const void *key2) {
   return key1 == key2;
}
 
/* Hash key compare function. Only use in string hash table. */
static int string_cmp_pointer(const void *key1, const void *key2) {
   return !strcmp(key1, key2);
}
 
/* Hash table find mapping function, it is a linchpin in hash table. */
static struct hash_mapping* find_mapping(struct hashtable *ht, const void *key) {
   struct hash_mapping *mapping = ht->mappings +
               HASH_POSITION(key, ht->hash_func, ht->size);

   if(NON_EMPTY(mapping) && !ht->test_func(mapping->key, key)) {
      unsigned long i = 0;
      for(; i < ht->size; ++i) {
         struct hash_mapping *mp = ht->mappings + i;
         if(!NON_EMPTY(mp))
            mapping = mp;
         if(NON_EMPTY(mp) && ht->test_func(mp->key, key)) {
            mapping = mp;
            break;
         }
      }   /* Loop end. */
   }
   return mapping;
}


/**************************************************************************
 * Hash table public functions.
 **************************************************************************/

struct hashtable*  hashtable_create(unsigned long size, hash_func_t hash_func,
                                                test_func_t test_func) {
   struct hashtable *ht=malloc(sizeof(struct hashtable));

   unsigned long hsize = prime_size(size + 1, &ht->prime_offset);
   ht->mappings = malloc(hsize * sizeof(struct hash_mapping));
   memset(ht->mappings, INVALID_PTR_BYTE, hsize * sizeof(struct hash_mapping));
  
   ht->hash_func = hash_func ? hash_func : hash_pointer;
   ht->test_func = test_func ? test_func : cmp_pointer;
   ht->count = 0;
   ht->size = hsize;
   ht->prime_offset = 0;
   ht->resize_threshold = hsize * HASH_MAX_FULLNESS;

   return ht;
}
 
struct hashtable*  make_string_hashtable(unsigned long size) {
   return hashtable_create(size, hash_string, string_cmp_pointer);
}
 
int hashtable_put(struct hashtable *ht, const void *key, void *value) {
   if(ht->count >= ht->resize_threshold)
      grow_hashtable(ht);
  
   struct hash_mapping *mapping = find_mapping(ht, key);
   if(NON_EMPTY(mapping))
      return 0;
  
   mapping->key = (void*)key;
   mapping->value = value;
   ht->count += 1;

   return 1;
}
 
void* hashtable_get(struct hashtable *ht, const void *key) {
   struct hash_mapping *mapping = find_mapping(ht, key);
   return NON_EMPTY(mapping) ? mapping->value : NULL;
}
 
int hashtable_remove(struct hashtable *ht, const void *key) {
   struct hash_mapping *mapping = find_mapping(ht, key);
   if(!NON_EMPTY(mapping))  /* Not found. */
      return 0;

   /* Remove item. */
   memset(mapping, INVALID_PTR_BYTE, sizeof(struct hash_mapping));
   ht->count -= 1;

   return 1;
}
 
int hashtable_contains(struct hashtable *ht, const void *key) {
   return NON_EMPTY(find_mapping(ht, key));
}
 
int hashtable_set(struct hashtable *ht, const void *key, void *newvalue) {
   struct hash_mapping *mapping = find_mapping(ht, key);
   if(!NON_EMPTY(mapping)) /* Not exist. */
      return 0;

   /* Update the item. */
   mapping->value = newvalue;

   return 1;
}
 
unsigned long hashtable_count(struct hashtable *ht) {
   return ht->count;
}

void hashtable_map(struct hashtable *ht,
                   int(*mapfunc)(void*, void*, void*), void* maparg) {
   unsigned i = 0, hsize = ht->size;
   struct hash_mapping *mp;
   for(; i < hsize; ++i) {
      mp = ht->mappings + i;
      if(NON_EMPTY(mp) && !mapfunc(mp->key, mp->value, maparg))
         return;
   }
}

void hashtable_clear(struct hashtable *ht) {
   memset(ht->mappings, INVALID_PTR_BYTE, ht->size * sizeof(struct hash_mapping));
   ht->count = 0;
}
 
void hashtable_close(struct hashtable *ht) {
   free(ht->mappings);
   free(ht);
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值