1、哈希表概念
哈希表支持一种最有效的检索方法:散列。从根本上说,一个哈希表包含一个数组,通过特殊的索引值(键)来访问数组中的元素。哈希表的主要思想是通过一个哈希函数在所有可能的键与槽位之间建立一张映射表。哈希函数每次接受一个键将返回与键位相对应的哈希编码或哈希值,键的数据类型可以多种多样,但是哈希值的类型只能是整型。
2、哈希表的类型
(1)链式哈希表:是指将数据存储在“桶”(bucket)中的哈希表。每个“桶”都是一个链表,且链表的容量能够随着冲突的增加而增大。
(2)开地址哈希表:是指将数据存储在本身中,而不是“桶”中的哈希表,它通过各种探查方法来避免冲突问题。
3、哈希表的主要应用
数据库系统、符号表、标签缓冲区、数据字典、关联数组
4、哈希表的实现代码
(1)链式哈希表
/*chtlb.h*/
#ifndef CHTBL_H
#define CHTBL_H
#include <stdlib.h>
#include "list.h"
/*define a structure for chained hash table*/
typedef struct CHTbl_
{
int buckets;
int (*h)(const void *key);
int (*match)(const void *key1,const void *key2);
void (*destroy)(void *data);
int size;
List *table;
}CHTbl;
/*public interface*/
int chtbl_init(CHTbl *htbl,int buckets,int (*h)(const void *key),
int (*match)(const void *key1,const void *key2),void (*destroy)(void *data));
void chtbl_destroy(CHTbl *htbl);
int chtbl_insert(CHTbl *htbl,const void *data);
int chtbl_remove(CHTbl *htbl,void **data);
int chtbl_lookup(const CHTbl *htbl,void **data);
#define chtbl_size(htbl) ((htbl)->size)
#endif
/*chtbl.c*/
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "chtbl.h"
int chtbl_init(CHTbl *htbl,int buckets,int (*h)(const void *key),
int (*match)(const void *key1,const void *key2),void (*destroy)(void *data))
{
int i;
/*alloate space for the hash table*/
if((htbl->table=(List *)malloc(buckets*sizeof(List)))==NULL)
return -1;
/*initialize the buckets*/
htbl->buckets=buckets;
for(i=0;i<htbl->buckets;i++)
list_init(&htbl->table[i],destroy);
/*encapsulate the function*/
htbl->h=h;
htbl->match=match;
htbl->destroy=destroy;
/*initialize the number of elements in the table*/
htbl->size=0;
return 0;
}
void chtbl_destroy(CHTbl *htbl)
{
int i;
/*destroy each buckets*/
for(i=0;i<htbl->buckets;i++)
{
list_destroy(&htbl->table[i]);
}
/*free the storage alloctee for the hash table*/
free(htbl->table);
/*clear the structure sa precatution*/
memset(htbl,0,sizeof(CHTbl));
return ;
}
int chtbl_insert(CHTbl *htbl,const void *data)
{
void *temp;
int bucket,retval;
/*do nothing if the data is already in the table*/
temp=(void *)data;
if(chtbl_lookup(htbl,&temp)==0)
return 1;
/*hash the key*/
bucket=htbl->h(data)%htbl->buckets;
/*insert the data into the bucket*/
if((retval=list_ins_next(&htbl->table[bucket],NULL,data))==0)
htbl->size++;
return retval;
}
int chtbl_remove(CHTbl *htbl,void **data)
{
ListElmt *element,*prev;
int bucket;
/*hash the key*/
bucket=htbl->h(*data)%htbl->buckets;
/*search for the data in the bucket*/
prev=NULL;
for(element=list_head(&htbl->table[bucket]);element!=NULL;element=list_next(element))
{
if(htbl->match(*data,list_data(element)))
{
/*remove the data from the bucket*/
if(list_rem_next(&htbl->table[bucket],prev,data)==0)
{
htbl->size++;
return 0;
}
else
{
return -1;
}
}
prev=element;
}
/*return that the data was not found*/
return -1;
}
int chtbl_lookup(const CHTbl *htbl,void **data)
{
ListElmt *element ;
int bucket;
/*hash the key*/
bucket=htbl->h(*data)%htbl->buckets;
/*search for the data in the bucket*/
for(element=list_head(&htbl->table[bucket]);element!=NULL;element=list_next(element))
{
if(htbl->match(*data,list_data(element)))
{
/*pass back the data from the table*/
*data=list_data(element);
return 0;
}
}
/*return that the data was not found*/
return -1;
}
应用实例:
后续补上
(2)开地址哈希表
/*ohtbl.h*/
#ifndef OCHTBL_H
#define OCHTBL_H
#include <stdlib.h>
/*define a structure for open-address hash table*/
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;
}OHTbl;
/*public interface*/
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 "ohtbl.h"
/*reserve a sentinel memory address for vacated element*/
static char vacated;
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;
/*alloate space for the hash table*/
if((htbl->table=(void **)malloc(positions*sizeof(void *)))==NULL)
return -1;
/*initialize the buckets*/
htbl->positions=positions;
for(i=0;i<htbl->positions;i++)
htbl->table[i]=NULL;
/*set the vacated member to the sentinel memory address reserved for this*/
htbl->vacated=&vacated;
/*encapsulate the function*/
htbl->h1=h1;
htbl->h2=h2;
htbl->match=match;
htbl->destroy=destroy;
/*initialize the number of elements in the table*/
htbl->size=0;
return 0;
}
void ohtbl_destroy(OHTbl *htbl)
{
int i;
if(htbl->destroy!=NULL)
{
/*call a user-defined function to free dynamically allocated data*/
for(i=0;i<htbl->positions;i++)
{
if(htbl->table[i]!=NULL && htbl->table[i]!=htbl->vacated)
htbl->destroy(&htbl->table[i]);
}
}
/*free the storage alloctee for the hash table*/
free(htbl->table);
/*clear the structure sa precatution*/
memset(htbl,0,sizeof(OHTbl));
return ;
}
int ohtbl_insert(OHTbl *htbl,const void *data)
{
void *temp;
int i,position;
/*do not exceed the number of positions in the table*/
if(htbl->size==htbl->positions)
return -1;
/*do nothing if the data is already in the table*/
temp=(void *)data;
if(ohtbl_lookup(htbl,&temp)==0)
return 1;
/*use double hashing to hash the key*/
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)
{
/*insert the data into the table*/
htbl->table[position]=(void *)data;
htbl->size++;
return 0;
}
}
/*return that the hash function were selecte incorrectly*/
return -1;
}
int ohtbl_remove(OHTbl *htbl,void **data)
{
int position,i;
/*use double hashing to hash the key*/
for(i=0;i<htbl->positions;i++)
{
position=(htbl->h1(data)+(i*htbl->h2(data)))%htbl->positions;
if(htbl->table[position]==NULL)
{
/*return that the data was not found*/
return -1;
}
else if(htbl->table[position]==htbl->vacated)
{
/*search beyond vacated from the table*/
continue;
}
else if(htbl->match(htbl->table[position],*data))
{
/*pass back the data from the table*/
*data=htbl->table[position];
htbl->table[position]=htbl->vacated;
htbl->size--;
return 0;
}
}
/*return that the data was not found*/
return -1;
}
int ohtbl_lookup(const OHTbl *htbl,void **data)
{
int position,i;
/*use double hashing to hash the key*/
for(i=0;i<htbl->positions;i++)
{
position=(htbl->h1(data)+(i*htbl->h2(data)))%htbl->positions;
if(htbl->table[position]==NULL)
{
/*return that the data was not found*/
return -1;
}
else if(htbl->match(htbl->table[position],*data))
{
/*pass back the data from the table*/
*data=htbl->table[position];
return 0;
}
}
/*return that the data was not found*/
return -1;
}
应用实例:
后续补上