算法学习之哈希表实现
来源:互联网 发布:邮箱域名大全 编辑:程序博客网 时间:2024/06/07 03:54
哈希表是一个键值对的数据结构,经常用于数据库索引,map,缓存等地方。可以表示成value = f(key),查找效率很高。哈希表实现最关键的地方是哈希函数的选择,好的哈希函数可以均匀分布,冲突小。现在工业界最常用的哈希函数是murmur,memcached和nginx使用的就是murmur。简单常用的哈希函数构造法有:1.直接定值法,利用key设计一个线性函数 f=a*key+b; 2.数字分析法,主要抽取部分数字进行循环左移,右移,相加减等各种操作。3.平方取中法。4.折叠法。5.除留余数法等。
哈希表冲突处理,哈希函数是会发生冲突的,不同的key计算出了相同的hashcode。处理的方法有闭散列法和开散列法。1.闭散列法就是所有的操作还在原来的存储空间,没有开辟新的存储空间。线性探测法:f(key)=(f(key)+1)mod n。
双重散列法:hash函数产生冲突时,调用rehash函数重新计算hash值。2.开散列法也称为拉链法,用链表组织整个哈希表,拉链法是用的最多的一种方法。
实现一个c语言版的存储字符串类型的hashmap。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define DEFAULT_INITIAL_CAPACITY 1 << 4 //哈希表默认初始化容量 #define MAXIMUM_CAPACITY 1 << 30 //哈希表最大容量 #define DEFAULT_LOAD_FACTOR 0.75F //哈希表负载系数,当系数越大占用空间越大,查询效率越高,系数越小占用空间越小,查询效率变低,此系数可调最佳0.75,如有需求可以自己调整 struct hlist_node { struct hlist_node **prev; //如果用双向链表组织哈希表可以使用,本程序是用单链表组织的 struct hlist_node *next; }; struct hlist_head { struct hlist_node *first; }; struct node { struct hlist_node hlist_node; char *key; char *value; }; struct hash_map { struct hlist_head *table; //哈希表基地址 int length; //哈希表头结点长度 int size; //k-v键值对个数 int threshold; //哈希表阈值 }; /*计算hashcode,java jdk1.8的计算方法,通过关键字的地址计算关键字的哈希值,此哈希函数散列情况较好 */static int hash(char *key) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*key) { hash = hash * seed + (*key++); } return (hash & 0x7FFFFFFF); } /*当哈希表内存不够用时,扩容,扩容的时候把旧哈希表中的内容复制到新的哈希表中*/ static void resize(struct hash_map *map) { int old_cap = map->length; int new_cap,i; if(old_cap >= MAXIMUM_CAPACITY) { map->threshold = MAXIMUM_CAPACITY; } else if((new_cap = old_cap << 1) < MAXIMUM_CAPACITY && old_cap >= DEFAULT_INITIAL_CAPACITY){ map->threshold = map->threshold << 1; map->length = new_cap; } struct hlist_head *old_table = map->table; map->table = (struct hlist_head*)calloc(map->length,sizeof(struct hlist_head)); for(i = 0; i < old_cap; i++) { if(old_table[i].first != NULL) { struct hlist_node *p = old_table[i].first; if(p->next == NULL) { map->table[hash(((struct node*)p)->key) & (new_cap - 1)].first = p; } else { struct hlist_node *low_head = NULL,*low_tail = NULL; struct hlist_node *high_head = NULL, *high_tail = NULL; while(p != NULL) { if(hash(((struct node*)p)->key) & old_cap == 0) { if(low_tail == NULL) low_head = p; else low_tail->next = p; low_tail = p; } else { if(high_tail == NULL) high_head = p; else high_tail->next = p; high_tail = p; } p = p->next; } if(low_tail != NULL) { low_tail->next = NULL; map->table[i].first = low_head; } if(high_tail != NULL) { high_tail->next = NULL; map->table[i + old_cap].first = high_head; } } } } free(old_table); } /*初始化哈希表,获取哈希表对象指针*/ static struct hash_map *new_hash_map() { struct hash_map *hash_map = (struct hash_map*)malloc(sizeof(struct hash_map)); hash_map->length = DEFAULT_INITIAL_CAPACITY; hash_map->threshold = (int)(DEFAULT_LOAD_FACTOR * (DEFAULT_INITIAL_CAPACITY)); hash_map->size = 0; hash_map->table = (struct hlist_head*)calloc(hash_map->length,sizeof(struct hlist_head)); return hash_map; } /*初始化哈希表节点*/ static struct hlist_node *new_node(char *key,char *value) { struct node *node = (struct node*)malloc(sizeof(struct node)); node->key = key; node->value = value; node->hlist_node.next = NULL; return &(node->hlist_node); } /*向哈希表中添加值*/ static int put_val(struct hash_map *map,int hash,char *key,char *value) { struct hlist_node *p; int i; int n = map->length; /*如果此节点为空,说明这个链表还没有哈希映射*/ if((p = map->table[i = (n-1) & hash].first) == NULL) { map->table[i].first = new_node(key,value); } else { struct node *e = NULL; /*遍历链表*/ if(!strcmp(((struct node*)p)->key,key)) { e = p; } while(p->next != NULL) { struct node *tmp = (struct node*)p; /*如果有相等的key,则需要修改此key对应的value,所以记下这个节点*/ if(!strcmp(tmp->key,key)) { e = tmp; break; } p = p->next; } /*如果没有相同的key则在链表末尾插入新节点*/ if(!e) { p->next = new_node(key,value); } else { /*否则更改key对应的value*/ e->value = value; return 1; } } if(++map->size > map->threshold) resize(map); return 0; } int put(struct hash_map *map,char *key,char *value) { return put_val(map,hash(key),key,value); } struct hlist_node *get_node(struct hash_map *map,int hash,char *key) { struct hlist_node *p; int n; if(map->table != NULL && (n = map->length) > 0 && (p = map->table[(n-1) & hash].first) != NULL){ struct node *tmp; while(p != NULL) { tmp = (struct node*)p; if(!strcmp(tmp->key,key)) { return p; } p = p->next; } } return NULL; } char *get(struct hash_map *map,char *key) { struct node *e; return (e = (struct node*)get_node(map,hash(key),key)) == NULL ? NULL : e->value; } int main() { struct hash_map *map = new_hash_map(); put(map,"中国","北京"); put(map,"美国","华盛顿"); put(map,"俄罗斯","莫斯科"); put(map,"日本","东京"); printf("%s\n",get(map,"中国")); printf("%s\n",get(map,"俄罗斯")); return 0; }
阅读全文
0 0
- 算法学习之哈希表实现
- Hadoop学习之PageRank算法并行实现
- C++学习之二叉树算法实现
- 机器学习之PYTHON实现KNN算法
- 算法学习之java实现快速排序
- 算法学习之java实现插入排序
- 算法学习之java实现希尔排序
- 算法学习之java实现归并排序
- 算法学习之java实现二分查找
- 算法学习之栈的实现
- 机器学习之KNN算法python实现
- 机器学习之决策树算法python实现
- 机器学习之CART算法python实现
- 【机器学习算法】之KNN算法的实现
- 【机器学习算法】之决策树算法的实现
- 机器学习算法之Logistic Regression算法实现
- 机器学习算法之KNN算法,python实现
- 机器学习算法之AdaBoost算法python实现
- 深度解析PHP、JAVA如何实现微信支付服务端接口
- Unity优化大全(一)之CPU-DrawCall- Batching
- [李景山php]按照发起的方式,DDoS可以简单分为三类
- leetcode 373. Find K Pairs with Smallest Sums 优先队列
- html转义
- 算法学习之哈希表实现
- vi
- Java类中变量的初始化/赋值过程
- 67. Add Binary
- 关于phpcms V9的调用栏目图片的调用方法
- Linux/Android——input系统之 kernel层 与 frameworks层交互 (五)
- 【数据库】使用Collection.setAutoCommit(false)的注意事项
- android入门
- unittest 基础之 —— TestResult