开地址哈希函数的接口定义

基本的操作包括:初始化开地址哈希表、销毁开地址哈希表、插入元素、删除元素、查找元素、获取元素个数。

各种操作的定义如下:

ohtbl_init


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));

返回值  如果哈希表初始化成功,返回0;否则返回-1 。

描述  初始化开地址哈希表htbl。在对哈希表进行其他操作之前,必须首先进行初始化。

参数positions 指定表中的槽位个数。函数指针h1,h2用来指定用户定义的辅助哈希函数以完成双散列过程。函数指针match指向一个用户定义的函数,此函数用于判断两个键是否匹配,它的使用方法与chtbl_init中的match类似。函数指针destroy通过调用ohtbl_destroy来释放动态分配的内存空间,同样它与ohtbl_init中参数的使用方法类似。如果哈希函数表中的数据不需要释放,那么destroy应该指向NULL。

复杂度  O(m),m是哈希表中槽的个数。

ohtbl_destroy


void ohtbl_destroy (OHTbl *htbl ) ;

返回值  无 。

描述  销毁htbl指定的开地址哈希表。在调用ohtbl_destroy之后不再允许进行其他操作,除非再次初始化。

ohtbl_destroy会删除哈希表中的所有元素,并同时释放ohtbl_init中参数destroy不为NULL的成员所占用的内存空间。

复杂度  O(m),m是哈希表中槽的个数。

ohtbl_insert


int ohtbl_insert (OHTbl *htbl,const void *data ) ;

返回值  如果插入元素成功,返回0;如果哈希表中已经包含此元素,返回1;否则,返回-1 。

描述  向htbl指定的开地址哈希表中插入一个元素

新元素包含一个指向data的指针,因此只要元素仍然存在于哈希表中,此指针就一直有效。与data相关的空间将由函数的调用者来管理。

复杂度  O(1)。

ohtbl_remove


int ohtbl_remove (OHTbl *htbl,const void **data ) ;

返回值  如果删除元素成功,返回0;否则,返回-1 。

描述  从htbl指定的开地址哈希表中删除与data匹配的元素

返回时,data指向已经删除元素中存储的数据。与data相关的内存空间将由函数调用者来管理。

复杂度  O(1)。

ohtbl_lookup


int ohtbl_lookup (const OHTbl *htbl,const void **data ) ;

返回值  如果在表中找到元素,返回0;否则,返回-1 。

描述  查找htbl指定的开地址哈希表中是否有与data匹配的元素

如果找到,在函数返回时,data指向哈希表中相匹配元素的数据。

复杂度  O(1)。

ohtbl_size


int ohtbl_size (const OHTbl *htbl ) ;

返回值  哈希表中元素的个数。

描述  获取哈希表中元素个数的宏

复杂度  O(1)。

开地址哈希表的实现与分析

实现分为两个文件,一是开地址哈希表的头文件,一是抽象数据类型的实现文件。

示例1:开地址哈希表的头文件

/*ohtbl.h*/
#ifndef OHTBL_H
#define OHTBL_H #include <stdlib.h>
/*定义开地址哈希表的数据结构*/
typedef struct OHTbl_
{
int positions; /*1指明哈希表中分配的槽位数目*/
void *vacated; /*2指向一个特殊的地址空间,这个特殊的地址上曾经删除过一个元素*/ int (*h1)(const void *key); /*3辅助哈希函数*/
int (*h2)(const void *key); /*4辅助哈希函数*/
int (*match)(const void *key1,const void *key2); /*5判断两个元素是否匹配*/
void (*destroy)(void *data); /*6销毁函数*/ int size; /*7现有的元素数目*/
void **table; /*8存储元素的数组*/
} 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_H

示例2:开地址哈希表抽象数据类型的实现

/*ohtbl.c*/
#include <stdlib.h>
#include <string.h> #include "ohtbl.h" /*为空出的元素预留一个特殊的内存地址*/
static char vacated; /*ohtbl_init 初始化htbl指定的开地址哈希表*/
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; /*初始化每个槽位,把每个槽位的指针设置为NULL*/
htbl->positions = positions;
for(i=0; i<htbl->positions; i++)
htbl->table[i] = NULL;    /*将空出的成员设置为为此保留的特殊内存地址*/
    htbl->vacated = &vacated;
    
    /*封装4个函数*/
    htbl->h1 = h1;
    htbl->h2 = h2;
    htbl->match = match;
    htbl->destroy=destroy;
    
    /*初始化元素数量*/
    htbl->size = 0;
    
    return 0;
} /*ohtbl_destroy 销毁htbl指定的开地址式哈希表*/
void 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]);
}
}
/*释放表空间*/
free(htbl->table); /*清除数据结构*/
memset(htbl,0,sizeof(OHTbl); return;
} /*ohtbl_insert 向表中插入元素*/
int ohtbl_insert(OHTbl *htbl,const void *data)
{
void *temp;
int position,i; /*因为开地址哈希表有固定的大小,所以在插入之前必须保证有足够的空间放置元素*/
if(htbl->size == htbl->positions)
return -1; /*相同的键不允许重复插入表中,插入之前调用htbl_lookup检查是否有相同的元素*/
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;
} /*ohtbl_remove 删除htbl指定表中与data相匹配的元素*/
int ohtbl_remove(OHTbl *htbl,void **data)
{
int position,i; /*通过双散列定位到要删除元素的位置*/
for(i=0; i<htbl->positions; i++)
{
position = (htbl->h1(*data) + (i * h2(*data))) % htbl->positions ; if(htbl->table[position] == NULL)
{
/*没有找到匹配的数据*/
return -1;
}
else if (htbl->table[position] == htbl->vacated)
{
/*查找到了突出的位置,继续搜索*/
continue;
}
else if (htbl->match(htbl->table[position],*data))
{
/*将data指向正在删除的数据*/
*data = htbl->table[position];
/*将此槽位的地址放到vacated成员中*/
htbl->[position] = htbl->vacated;
htbl->size--;
return 0;
}
}
/*如果没有找到元素,则返回-1*/
return -1;
} /*ohtbl_lookup 查找htbl指定的表中,与data相匹配的元素*/
int ohtbl_lookup(const OHTbl *htbl,void **data)
{
int position,i; for(i=0; i<htbl->positions; i++)
{
position = (htbl->h1(*data) + (i * htbl->h2(*data)))% htbl->positions; if(htbl->table[position] == NULL)
{
/*没有找到数据*/
retun -1;
}
else if(htbl->match(htbl->table[position],*data))
{
/*将data指向找到的数据*/
*data = htbl->table[position];
return 0;
}
}
return -1;
}

开地址哈希表(Hash Table)的接口定义与实现分析的更多相关文章

  1. 开地址哈希表(Hash Table)的原理描述与冲突解决

    在开地址哈希表中,元素存放在表本身中.这对于某些依赖固定大小表的应用来说非常有用.因为不像链式哈希表在每个槽位上有一个"桶"来存储冲突的元素,所以开地址哈希表需要通过另一种方法来解 ...

  2. 算法与数据结构基础 - 哈希表(Hash Table)

    Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...

  3. 数据结构 哈希表(Hash Table)_哈希概述

    哈希表支持一种最有效的检索方法:散列. 从根来上说,一个哈希表包含一个数组,通过特殊的索引值(键)来访问数组中的元素. 哈希表的主要思想是通过一个哈希函数,在所有可能的键与槽位之间建立一张映射表.哈希 ...

  4. PHP关联数组和哈希表(hash table) 未指定

    PHP有数据的一个非常重要的一类,就是关联数组.又称为哈希表(hash table),是一种很好用的数据结构. 在程序中.我们可能会遇到须要消重的问题,举一个最简单的模型: 有一份username列表 ...

  5. 词典(二) 哈希表(Hash table)

    散列表(hashtable)是一种高效的词典结构,可以在期望的常数时间内实现对词典的所有接口的操作.散列完全摒弃了关键码有序的条件,所以可以突破CBA式算法的复杂度界限. 散列表 逻辑上,有一系列可以 ...

  6. 什么叫哈希表(Hash Table)

    散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. - 数据结构 ...

  7. 哈希表(Hash table)

  8. Redis原理再学习04:数据结构-哈希表hash表(dict字典)

    哈希函数简介 哈希函数(hash function),又叫散列函数,哈希算法.散列函数把数据"压缩"成摘要,有的也叫"指纹",它使数据量变小且数据格式大小也固定 ...

  9. 数据结构 链式哈希表(Hash Table)的接口定义与实现分析(完整代码)

    链式哈希表的接口定义 关于哈希表与链式哈希表的描述可以参阅:http://www.cnblogs.com/idreamo/p/7990860.html 链式哈希表的操作与属性有:初始化.销毁.插入元素 ...

随机推荐

  1. python3之内置函数

    1.abs() 取数字的绝对值 >>> print(abs(-28)) 28 >>> print(abs(-2.34)) 2.34 >>> pri ...

  2. 【读书笔记】【深入理解ES6】#9-JavaScript中的类

    大多数面向对象的编程语言都支持类和类继承的特性,而JavaScript却不支持这些特性,只能通过其他方法定义并关联多个相似的对象.这个状态一直从ECMAScript 1持续到ECMAScript 5. ...

  3. 使用docker+jenkins构建nodejs前端项目

    前文使用Docker搭建Jenkins+Docker持续集成环境我们已经搭建了基于docker+jenkins的持续集成环境,并构建了基于maven的项目.这一节,我们继续扩展功能,增加对Nodejs ...

  4. 常见的VPS虚拟化架构:OpenVZ、Xen、Hyper-V、KVM、VMWare OpenVZ

    OpenVZ OpenVZ特点是,它是直接调用母服务器的内核,所以会导致部分软件无法使用,以及部分内核文件是无法修改. OpenVZ适用人群:新手.低预算客户 OpenVZ注意事项:资源不是自己独有的 ...

  5. Android 线程_笔记

    多线程 一.为什么要使用多线程 1.提高用户体验或避免ANR 在事件处理代码中需要使用多线程,响应时间超过5s,即会出现ANR(Application is not responding),并因为响应 ...

  6. cookie/session(过时的写法)

    cookie存在客户端的浏览器中,不太安全,容易被窃取,,session被存在服务器中(类似于字典中的value,),服务器会给浏览器返回这个value的key值,下次进来直接根据key取value. ...

  7. 循序渐进之Spring AOP(3) - 配置代理

    上一篇介绍了几种Advice(增强),并通过代码演示了生成代理的方式,下面来看通过配置文件配置方式把Advice织入目标类. 注意,配置文件方式仍然不是spring AOP的最好方式,学习配置方式也是 ...

  8. meterpreter_paranoid_mode.sh允许用户安全上演/无级连接Meterpreter经检查合格证书的处理程序正在连接到

    刚刚看完即刻安全大咖的新姿势感觉很6逼,结果成功了meterpreter_paranoid_mode.sh允许用户安全上演/无级连接Meterpreter经检查合格证书的处理程序正在连接到. 我们开始 ...

  9. bzoj:3616: War

    Description 小x所在的世界正在经历一场在k个阵营之间的战争.每个阵营有若干个炮塔,每个炮塔由攻击系统和防御系统组成.第i个炮塔可以攻击到离它欧几里德距离小于等于ri 或者曼哈顿距离小于等于 ...

  10. HDU 1010 Tempter of the Bone【DFS经典题+奇偶剪枝详解】

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...