您的位置:首页 > 编程语言 > C语言/C++

哈希表系列:初探哈希(二),c语言实现

2015-07-21 19:20 429 查看
上次分析了哈希表的链地址法的实现,即采用“数组+链表”的数据结构。这次,介绍下用哈希桶的方式去解决哈希冲突,即通过哈希函数hash()将key转化为哈希值,然后根据桶的容量(桶的容量固定),且结合“除余法”定位到某个哈希下标,为该哈希值建立哈希桶(Bucket)。

完整的实现代码:链接。下面,针对里面关键的函数进行分析。

1、哈希表的关键函数分析

里面涉及的数据结构:
struct Pair {
char *key;
char *value;
};

struct Bucket {
unsigned int count;
Pair *pairs;
};

struct StrMap {
unsigned int count;
Bucket *buckets;
};
上面数据结构之间的关系可以通过下图理解:



空哈希表的建立:
StrMap * sm_new(unsigned int capacity)
{
StrMap *map;

map = (StrMap*)malloc(sizeof(StrMap));
if (map == NULL) {
return NULL;
}
map->count = capacity;
map->buckets = (Bucket*)malloc(map->count * sizeof(Bucket));
if (map->buckets == NULL) {
free(map);
return NULL;
}
memset(map->buckets, 0, map->count * sizeof(Bucket));
return map;
}


往哈希表里添加key值和value值:
int sm_put(StrMap *map, const char *key, const char *value)
{
unsigned int key_len, value_len, index;
Bucket *bucket;
Pair *tmp_pairs, *pair;
char *tmp_value;
char *new_key, *new_value;

if (map == NULL) {
return 0;
}
if (key == NULL || value == NULL) {
return 0;
}
key_len = strlen(key);
value_len = strlen(value);
/* Get a pointer to the bucket the key string hashes to */
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
/* Check if we can handle insertion by simply replacing
* an existing value in a key-value pair in the bucket.
*/
if ((pair = get_pair(bucket, key)) != NULL) {
/* The bucket contains a pair that matches the provided key,
* change the value for that pair to the new value.
*/
if (strlen(pair->value) < value_len) {
/* If the new value is larger than the old value, re-allocate
* space for the new larger value.
*/
tmp_value = (char*)realloc(pair->value, (value_len + 1) * sizeof(char));
if (tmp_value == NULL) {
return 0;
}
pair->value = tmp_value;
}
/* Copy the new value into the pair that matches the key */
strcpy(pair->value, value);
return 1;
}
/* Allocate space for a new key and value */
new_key = (char*)malloc((key_len + 1) * sizeof(char));
if (new_key == NULL) {
return 0;
}
new_value = (char*)malloc((value_len + 1) * sizeof(char));
if (new_value == NULL) {
free(new_key);
return 0;
}
/* Create a key-value pair */
if (bucket->count == 0) {
/* The bucket is empty, lazily allocate space for a single
* key-value pair.
*/
bucket->pairs = (Pair*)malloc(sizeof(Pair));
if (bucket->pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->count = 1;
}
else {
/* The bucket wasn't empty but no pair existed that matches the provided
* key, so create a new key-value pair.
*/
tmp_pairs = (Pair*)realloc(bucket->pairs, (bucket->count + 1) * sizeof(Pair));
if (tmp_pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->pairs = tmp_pairs;
bucket->count++;
}
/* Get the last pair in the chain for the bucket */
pair = &(bucket->pairs[bucket->count - 1]);
pair->key = new_key;
pair->value = new_value;
/* Copy the key and its value into the key-value pair */
strcpy(pair->key, key);
strcpy(pair->value, value);
return 1;
}


上述函数思路:
1)判断哈希表是否为空,否则return NULL;
2) 通过函数get_pair()判断key值是否存在哈希表中,若存在则将相应的value值覆盖;若不存在跳入3);
3)判断哈希桶是否为空,若满足则开辟首元素;否则即在哈希桶的末尾开辟内存,添加key值和value值;

根据key值,取出相应的value
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf)
{
unsigned int index;
Bucket *bucket;
Pair *pair;

if (map == NULL) {
return 0;
}
if (key == NULL) {
return 0;
}
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
pair = get_pair(bucket, key);
if (pair == NULL) {
return 0;
}
if (out_buf == NULL && n_out_buf == 0) {
return strlen(pair->value) + 1;
}
if (out_buf == NULL) {
return 0;
}
if (strlen(pair->value) >= n_out_buf) {
return 0;
}
strcpy(out_buf, pair->value);
return 1;
}


哈希函数
static unsigned long hash(const char *str)
{
unsigned long hash = 5381;
int c;

while (c = *str++) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}


2、哈希实验

主函数:
void main()
{
int hash_capacity;
char *str=(char*)malloc(sizeof(char)*size);
printf("hash_capacity is:");
scanf("hash_capacity is %d\n",&hash_capacity);

StrMap *c_map=sm_new(100);
sm_put(c_map,"LIN","588239");
sm_put(c_map,"address","Ningbo");

if (sm_get(c_map,"LIN",str,size))
{
printf("corresponding value is %s\n",str);
}

return;

}


实验结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: