C算法精解-----哈希表(2)
来源:互联网 发布:知乎一句话简介 编辑:程序博客网 时间:2024/05/30 19:32
前面对链式哈希表的定义、实现、分析的一下,感觉也不是想象中的那么难,只要把思路理清,在草稿纸上画下他的实现思路,代码阅读起来也就一目了然了。下次再看时,只要把当初画的草图一拿出来就知道,当初定义的函数接口:插入、删除、查找是怎么实现的。数据结构本身就是很抽象的东西。对初学者来说,画草图是很容易理解代码实现思路。
下面介绍另外一种哈希表的实现方法 :开地址哈希表的描述。
在链式哈希表中,元素存在在每个地址的桶中。而开地址哈希表,元素存放在表本身中。因为注定不能和链式哈希表一样解决冲突。在开地址哈希表中解决冲突的方式就是探查这个表,直到找个放这个元素的槽,或者找到这个元素。当然如果遍历完整个表也没有找到这个元素,说明元素没有在表中。
检索哈希表的效率主要有2个因素有关:哈希表的负载因子(元素的总个数处于桶的个数)和 元素均匀分布的程度。
线性探查
线性探查的哈希函数定义:h(k,i) = (h`(k)+i)mod m ,k是键(插入的元素),i表示探查的次数,i是大于等于0小于m.m槽个数。h`是一个辅助哈希函数。h`=k mod m.
下面一个简单例子介绍下:
双散列
最有效的探查开地址哈希表的方法之一,就是通过计算两个辅助哈希函数哈希编码的和来得到哈希编码。双散列的哈希函数定义为:
h(k,i) = (h1(k) + ih2(k)) mod m h1和 h2是两个辅助哈希函数
开地址哈希表的实现和分析
疑问:就是结构体中定义的一个变量vacated 在代码中的作用:个人理解没有起到什么实质的作用,就是保存了上一次删除操作的一个位置~。有其他更好理解的给解释下~
/*ohtbl.h*/#ifndef OHTBL_H#define OHTBL_H#include <stdlib.h>/*定义开地址哈希表结构体*/typedef struct Ohtbl_{ int positions;/*槽位的个数*/ void *vacated;/*指针将被初始化来指向一个特殊的地址空间, 来证明这个特殊地址上曾经删除过一个元素*/ int (*h1)(const void * key); int (*h2)(const void *key); int (*match)(const void *key1,const void *key2); void (*destroy)(void *data); int size;/*元素的个数*/ void **table;/*存储元素的数组(malloc申请)*/}Ohtbl;/*函数接口*/int ohtbl_init(Ohtbl *htbl,int positions,int (*h1)(const void *key),int (*h2)(const void *key),int (*match)(const void *key1,const void *key2),void (*destroy)(void *data));void ohtbl_destroy(Ohtbl *htbl);int ohtbl_insert(Ohtbl *htbl,const void *data);int ohtbl_remove(Ohtbl *htbl,void **data);int ohtbl_lookup(const Ohtbl *htbl,void **data);#define ohtbl_size(htbl) ((htbl) ->size)#endif
/*ohtbl.c*/#include <stdlib.h>#include <string.h>#include "./include/ohtbl.h"/*预订一个内存地位为腾出的元素*/static char vacated;/*结构体初始化 *return 初始化成功: 0, 失败:-1. */int ohtbl_init(Ohtbl * htbl, int positions, int(* h1)(const void * key), int(* h2)(const void * key), int(* match)(const void * key1, const void * key2), void(* destroy)(void * data)){ int i; /*申请空间为哈希表*/ if ((htbl ->table = (void **)malloc(positions *sizeof(void *))) == NULL) return -1; /*初始化每个positions*/ htbl ->positions = positions; for (i = 0; i < htbl->positions; i++) htbl -> table[i] = NULL; /*设置腾出成员的内存地址*/ htbl->vacated = &vacated; /*初始化封装的函数*/ htbl -> h1 = h1; htbl -> h2 = h2; htbl ->match = match; htbl ->destroy = destroy; /*初始化元素个数*/ htbl ->size = 0; return 0;}/*开地址哈希表销毁 * * */ int ohtbl_destroy(Ohtbl * htbl){ int i; if (htbl ->destroy !=NULL){ /*使用用户定义的函数去释放存放数据的内存*/ for (i = 0; i < htbl ->positions; i++){ if (htbl ->table[i] != NULL && htbl ->table[i] != htbl ->vacated) htbl ->destroy(htbl ->table[i]); } } /*释放table 内存*/ free(htbl ->table); /*清空哈希表结构体*/ memest(htbl,0,sizeof(Ohtbl)); return;}/* 哈希表中插入元素 *return 初始化成功: 0, 失败:-1. * 数据已经在哈希表内返回:1 */int ohtbl_insert(Ohtbl * htbl, const void * data){ void *temp; int position = 0; int i = 0; /*但哈希表已经满的话返回-1*/ if (htbl ->size == htbl ->positions) return -1; /*如果数据已经在哈希表内,返回1*/ temp = (void *)data; if (ohtbl_lookup(htbl, &temp) == 0) return 1; /*找到哈希编码值存在数据*/ for (i = 0; i <htbl -> positions; i++){ /*获得哈希编码值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL || htbl ->table[position] ==htbl ->vacated){ /*插入数据*/ htbl ->table[position] = (void *)data; htbl ->size ++; return 0; } } return -1;}/* 删除哈希表数值 *return 初始化成功: 0, 失败:-1. */int ohtbl_remove(Ohtbl * htbl, void * * data){ int i = 0; int position = 0; if (htbl ->size == 0) return -1; for (i = 0; i <htbl -> positions; i++){ /*获得哈希编码值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL){/*表明元素未存放到哈希表内*/ return -1; } else if (htbl ->table[position] == htbl ->vacated){ /*搜索vacated 之外*/ continue; } else if(htbl -> match(htbl->table[position],*data)){ *data = htbl->table[position]; htbl->table[position] = htbl ->vacated; htbl->size --; return 0; } } return -1}/*查找数据 *return 初始化成功: 0, 失败:-1. */int ohtbl_lookup(const Ohtbl * htbl, void * * data){ int position = 0; int i = 0; for (i = 0; i <htbl -> positions; i++){ /*获得哈希编码值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL){/*表明元素未存放到哈希表内*/ return -1; } else if(htbl -> match(htbl->table[position],*data)){ *data = htbl->table[position]; return 0; } } return -1;}
- C算法精解-----哈希表(2)
- C算法精解-----哈希表(1)
- C算法精解---链表(2)
- 算法精解:C语言描述
- 《算法精解:C语言描述》勘误
- C算法精解---树的基础知识
- C算法精解---图(Graph)
- 算法精解:C语言描述
- C算法精解---树的基础知识
- 算法精解十一(C语言版)
- 算法精解十二(C语言版)
- 算法精解十三(C语言版)
- 算法精解十四(C语言版)
- 算法精解十五(C语言版)
- 算法精解十六(C语言版)
- 算法精解十七(C语言版)
- 算法精解十八(C语言版)
- 算法精解十九(C语言版)
- HDOJ 【C】 2011 多项式求和
- Minix源代码中的汇编
- cocos2d-x SimpleGame(4)如何检测碰撞
- ELMAH——可插拔错误日志工具
- HDU2203:亲和串
- C算法精解-----哈希表(2)
- windows内存池 一线程分配 一线程释放 无锁 安全?
- 构建ASP.NET网站十大必备工具
- ie6 a hover 属性失效解决办法
- [Eclipse]How to export eclipse rich client application?
- C语言优先级在嵌入式编程中的重要性
- 跟我一起写Makefile:书写命令
- ELMAH(ASP.NET错误日志记录与通知)系列文章-概念篇
- ElMAH(ASP.NET错误日志记录与通知)系列文章-基础应用篇