Swift51.com
麦子学院 头像
麦子学院  2016-12-21 15:42

Php内核中的HashTable相关使用详解

回复:0  查看:2208  
本文和大家分享的主要是php内核的HashTable相关使用,希望通过本文的分享,对大家学习php有所帮助。
  typedef struct _Bucket
  {
  char *key;
  void *value;
  struct _Bucket *next;
  } Bucket;
  typedef struct _HashTable
  {
  int size;
  int elem_num;
  Bucket** buckets;
  } HashTable;
  这个是一个简化过的哈希表结构
  Bucket是一个链表,而_HashTable用于存储hash值并指向真正的数据储存单位
  解决冲突算法DJBX33A
  而链表是为了解决冲突用的,冲突解决采用DJBX33A算法,算法的内容如下
  inlineunsignedtime33(charconst*str,intlen)
  {
  unsigned long hash = 5381;
  /* variant with the hash unrolled eight times */
  for (; len >= 8; len -= 8) {
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  hash = ((hash << 5) + hash) + *str++;
  }
  switch (len) {
  case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
  case 1: hash = ((hash << 5) + hash) + *str++; break;
  case 0: break;
  }
  return hash;
  }
Php内核中的HashTable相关使用详解 
HashTable的初始化
  初始化,申请空间并且设置初始化值
  inthash_init(HashTable *ht)
  {
  ht->size = HASH_TABLE_INIT_SIZE;
  ht->elem_num = 0;
  ht->buckets = (Bucket **)calloc(ht->size, sizeof(Bucket *));
  if(ht->buckets == NULL) return FAILED;
  LOG_MSG("[init]\tsize: %i\n", ht->size);
  return SUCCESS;
  }
  HashTable的插入
  插入函数,插入时验证key是否存在,存在更新value值,不存在并取发生冲突则创建新节点并插入到原有链表的头部
  inthash_insert(HashTable *ht,char*key,void*value)
  {
  // check if we need to resize the hashtable
  resize_hash_table_if_needed(ht);
  int index = HASH_INDEX(ht, key);
  Bucket *org_bucket = ht->buckets[index];
  Bucket *tmp_bucket = org_bucket;
  // check if the key exits already
  while(tmp_bucket)
  {
  if(strcmp(key, tmp_bucket->key) == 0)
  {
  LOG_MSG("[update]\tkey: %s\n", key);
  tmp_bucket->value = value;
  return SUCCESS;
  }
  tmp_bucket = tmp_bucket->next;
  }
  Bucket *bucket = (Bucket *)malloc(sizeof(Bucket));
  bucket->key = key;
  bucket->value = value;
  bucket->next = NULL;
  ht->elem_num += 1;
  if(org_bucket != NULL)
  {
  LOG_MSG("[collision]\tindex:%d key:%s\n", index, key);
  bucket->next = org_bucket;
  }
  ht->buckets[index]= bucket;
  LOG_MSG("[insert]\tindex:%d key:%s\tht(num:%d)\n",
  index, key, ht->elem_num);
  return SUCCESS;
  }
  HashTable的扩容
  当Hash表容量满了的时候,Hash表的性能会下降,这时候需要对Hash表进行扩容
  先把原来Hash表容量变成两倍,然后对其进行重新插入操作,时间复杂度为O(n)
  staticvoidresize_hash_table_if_needed(HashTable *ht)
  {
  if(ht->size - ht->elem_num < 1)
  {
  hash_resize(ht);
  }
  }
  staticinthash_resize(HashTable *ht)
  {
  // double the size
  int org_size = ht->size;
  ht->size = ht->size * 2;
  ht->elem_num = 0;
  LOG_MSG("[resize]\torg size: %i\tnew size: %i\n", org_size, ht->size);
  Bucket **buckets = (Bucket **)calloc(ht->size, sizeof(Bucket *));
  Bucket **org_buckets = ht->buckets;
  ht->buckets = buckets;
  int i = 0;
  for(i=0; i < org_size; ++i)
  {
  Bucket *cur = org_buckets ;
  Bucket *tmp;
  while(cur)
  {
  // rehash: insert again
  hash_insert(ht, cur->key, cur->value);
  // free the org bucket, but not the element
  tmp = cur;
  cur = cur->next;
  free(tmp);
  }
  }
  free(org_buckets);
  LOG_MSG("[resize] done\n");
  return SUCCESS;
  }
  HashTable的查找
  元素的查找和插入采取相同的策略,都是先获得hash值,然后取得bucket链表,随后比较键名进行查找
  inthash_lookup(HashTable *ht,char*key,void**result)
  {
  int index = HASH_INDEX(ht, key);
  Bucket *bucket = ht->buckets[index];
  if(bucket == NULL) goto failed;
  while(bucket)
  {
  if(strcmp(bucket->key, key) == 0)
  {
  LOG_MSG("[lookup]\t found %s\tindex:%i value: %p\n",
  key, index, bucket->value);
  *result = bucket->value;
  return SUCCESS;
  }
  bucket = bucket->next;
  }
  failed:
  LOG_MSG("[lookup]\t key:%s\tfailed\t\n", key);
  return FAILED;
}

来源:William的后花园