哈希表系列:初探哈希(二),c语言实现
2015-07-21 19:20
429 查看
上次分析了哈希表的链地址法的实现,即采用“数组+链表”的数据结构。这次,介绍下用哈希桶的方式去解决哈希冲突,即通过哈希函数hash()将key转化为哈希值,然后根据桶的容量(桶的容量固定),且结合“除余法”定位到某个哈希下标,为该哈希值建立哈希桶(Bucket)。
完整的实现代码:链接。下面,针对里面关键的函数进行分析。
空哈希表的建立:
往哈希表里添加key值和value值:
上述函数思路:
1)判断哈希表是否为空,否则return NULL;
2) 通过函数get_pair()判断key值是否存在哈希表中,若存在则将相应的value值覆盖;若不存在跳入3);
3)判断哈希桶是否为空,若满足则开辟首元素;否则即在哈希桶的末尾开辟内存,添加key值和value值;
根据key值,取出相应的value
哈希函数
实验结果:
完整的实现代码:链接。下面,针对里面关键的函数进行分析。
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; }
实验结果:
相关文章推荐
- OC语言数组
- C语言实现递归删除文件夹
- C语言基础6
- 12天学好C语言——记录我的C语言学习之路(Day 12)
- 12天学好C语言——记录我的C语言学习之路(Day 12)
- C++ 实现string的split
- 12天学好C语言——记录我的C语言学习之路(Day 11)
- 12天学好C语言——记录我的C语言学习之路(Day 11)
- POJ 2387
- C++ - 模板类模板成员函数(member function template)隐式处理(implicit)变化
- 深入分析C++引用
- c语言中如何妙用do...while(0)语句
- C/C++中extern关键字详解
- Qt、C++小票打印----网口
- C语言取整方法总结
- C/C++ typedef用法
- 12天学好C语言——记录我的C语言学习之路(Day 10)
- 12天学好C语言——记录我的C语言学习之路(Day 10)
- c++书籍
- 12天学好C语言——记录我的C语言学习之路(Day 9)