初始化的主要工作是为哈希表申请存储空间,函数中使用calloc函数的目的是确保
数据存储的槽为都初始化为0,以便后续在插入和查找时确认该槽为是否被占用。
int hash_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;
}
static void resize_hash_table_if_needed(HashTable *ht)
{
if(ht->size - ht->elem_num < 1)
{
hash_resize(ht);
}
}
static int hash_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[i];
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;
}
PHP中数组是基于哈希表实现的,依次给数组添加元素时,元素之间是有先后顺序的, 而这里的哈希表在物理位置上显然是接近平均分布的,这样是无法根据插入的先后顺序获取到这些元素的, 在PHP的实现中Bucket结构体还维护了另一个指针字段来维护元素之间的关系。 具体内容在后一小节PHP中的HashTable中进行详细说明。上面的例子就是PHP中实现的一个精简版。
本小节的HashTable实例完整代码可以在$TIPI_ROOT/book/sample/chapt03/03-01-01-hashtable目录中找到。 或者在github上浏览: https://github.com/reeze/tipi/tree/master/book/sample/chapt03/03-01-01-hashtable
http://www.php-internals.com/book/?p=chapt03/03-01-01-hashtable