哈希表的简单实现

来源:互联网 发布:2016中国家庭资产 知乎 编辑:程序博客网 时间:2024/05/18 18:52

     下面这个散列表的实现来自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);
    }
}
0 0