下面这个散列表的实现来自K&R,很经典。在其他场景中遇到的实现更复杂,基本原理不变,只是在hash算法,或者在快速查询上做了优化。
#include <stdio.h>
#include <stdlib.h>
//具有相同hash值构成的链表
struct nlist{
struct nlist
* next;
char * name; //key-定义的名字
char * defn; //value-替换文本
};
#define HASHSIZE 101 //桶的大小
static struct nlist
*hashtable[HASHSIZE]; //hash table
//字符串hash函数
unsigned hash( char *s){
unsigned hashval;
for(hashval
= 0; s != ‘\0‘; s++)
hashval = *s + hashval * 31; //the seed can
be 1313,131313 etc..
return hashval
% HASHSIZE;
}
//查找函数,在 hashtable中找字符串s所在的bucket
struct nlist *lookup( char *s){
struct nlist
*np;
for(np
= hashtable[hash(s)]; np; np = np-> next)
if (strcmp(s,
np->name ) == 0)
return np;
return NULL;
}
//加入函数,将(name, defn)加入到 hashtable中,如果已经存在则更新
//如果无足够空间申请表项则返回空
struct nlist *install( char *name, char *defn){
struct nlist
*np;
unsigned hashval;
if((np
= lookup(name)) == NULL){ //要插入的key不存在
np = ( struct nlist
*)malloc( sizeof( struct nlist));
if (np
== NULL || (np-> name =
strdup(name)) == NULL)
return NULL;
hashval = hash(name);
//放入相应的桶中
np-> next =
hashtable[hashval];
hashtable[hashval] = np;
} else{ //已存在,则更新
free(( void *)np->defn );
}
//最后统一处理 value
if((np-> defn =
strdup(defn) ) == NULL)
return NULL;
return np;
}
//从哈希表中删除一个key-value
void undef( char *s){
unsigned h;
struct nlist
*prev, *np;
prev = NULL;
h = hash(s);
for(np
= hashtable[h]; np != NULL; np = np-> next){
if (strcmp(s,
np->name ) == 0)
break ; //找到相应的结点
prev = np; // 保留目标结点的前一个结点
}
if(np
!= NULL){
if (prev
== NULL) //说明要删除的是桶的第一个成员
hashtable[h] = np-> next;
else
prev-> next =
np-> next;
free(( void *)np->name ); //切记要分别释放
free(( void *)np->defn );
free(( void *)np);
}
}