hashmap
Posted renhl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hashmap相关的知识,希望对你有一定的参考价值。
hashmap.h
#ifndef foohashmaphfoo #define foohashmaphfoo /* $Id: hashmap.h 90 2004-07-17 14:12:30Z lennart $ */ /*** This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ struct pa_hashmap; struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); void* pa_hashmap_get(struct pa_hashmap *h, const void *key); int pa_hashmap_remove(struct pa_hashmap *h, const void *key); unsigned pa_hashmap_ncontents(struct pa_hashmap *h); #endif
hashmap.c
/* $Id: hashmap.c 90 2004-07-17 14:12:30Z lennart $ */ /*** This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <assert.h> #include <string.h> #include "hashmap.h" #include "idxset.h" struct hashmap_entry { //bucket_next, bucket_previous用于data数组,连接相邻的两个元素;next,previous用于first_entry的链表中两个相邻元素的连接 struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; //hash 值 unsigned hash; //key const void *key; //key 对应的data void *value; }; struct pa_hashmap { //data数组的大小,固定为1023 unsigned size; //index是由key进行hash后,对1023取余得到的 //将对应的 hashmap_entry *存入data[index]指定的链表 struct hashmap_entry **data; //对所有的元素进行存入链表中 struct hashmap_entry *first_entry; //hashmap_entry元素的个数 unsigned n_entries; //对key取hash的函数 unsigned (*hash_func) (const void *p); //key的比较函数 int (*compare_func) (const void*a, const void*b); }; //初始化pa_hashmap struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { struct pa_hashmap *h; h = malloc(sizeof(struct pa_hashmap)); assert(h); //data分配一个1023大小的数组,每个元素是hashmap_entry* h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); assert(h->data); memset(h->data, 0, sizeof(struct hashmap_entry*)*(h->size = 1023)); h->first_entry = NULL; h->n_entries = 0; h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; return h; } //将h中的e删除 //从两个双向链表中删除;删除元素本身;个数减1 static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { assert(e); //e->next为非空,表示不是链表的最后一个元素 if (e->next) e->next->previous = e->previous; //e->previous为非空,表示不是链表的第一个元素 if (e->previous) e->previous->next = e->next; else h->first_entry = e->next; //e->bucket_next为非空,表示不是data[index]指向的链表的最后一个元素 if (e->bucket_next) e->bucket_next->bucket_previous = e->bucket_previous; //e->bucket_previous为非空,表示不是data[index]指向的链表的第一个元素 if (e->bucket_previous) e->bucket_previous->bucket_next = e->bucket_next; else h->data[e->hash] = e->bucket_next; free(e); //个数减1 h->n_entries--; } //释放h //h->first_entry的链表指向所有的元素,对每个元素进行删除;释放data数组;释放h void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { assert(h); while (h->first_entry) { if (free_func) free_func(h->first_entry->value, userdata); remove(h, h->first_entry); } free(h->data); free(h); } //在h中取得hash (实际上也是由key得到的)和key指向的hashmap_entry* //用key得到hashmap_entry* static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; //在h->data[hash]的链表中,遍历查找key元素的hashmap_entry* for (e = h->data[hash]; e; e = e->bucket_next) if (h->compare_func(e->key, key) == 0) return e; return NULL; } //插入key和value到h中 //检查key是否重复,重复返回-1;不重复,插入到h->first_entry和h->data[hash]中链表的开头;数目加1 int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { struct hashmap_entry *e; unsigned hash; assert(h && key); //计算hash hash = h->hash_func(key) % h->size; //用hash和key获取hashmap_entry * if ((e = get(h, hash, key))) return -1; //如果存在,返回-1表示插入重复key e = malloc(sizeof(struct hashmap_entry)); assert(e); e->hash = hash; e->key = key; e->value = value; //插入到h->first_entry指向的双向链表的开头 e->previous = NULL; e->next = h->first_entry; if (h->first_entry) h->first_entry->previous = e; h->first_entry = e; //插入到h->data[hash]指向的双向链表的开头 e->bucket_previous = NULL; e->bucket_next = h->data[hash]; if (h->data[hash]) h->data[hash]->bucket_previous = e; h->data[hash] = e; //数目加1 h->n_entries ++; return 0; } //在h中取得key对应的data //有key计算hash;由hash和key取得hashmap_entry *;返回hashmap_entry *中的value void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; assert(h && key); //由key计算hash hash = h->hash_func(key) % h->size; //由key和hash取得hashmap_entry * if (!(e = get(h, hash, key))) return NULL; //key没有插入到h中 return e->value; //返回key对应的data } //删除key指定的元素 int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; assert(h && key); //由key计算hash hash = h->hash_func(key) % h->size; //由key和hash取得hashmap_entry * if (!(e = get(h, hash, key))) return 1; //删除h中的e元素 remove(h, e); return 0; } //返回元素的个数 unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { return h->n_entries; }
以上是关于hashmap的主要内容,如果未能解决你的问题,请参考以下文章