C语言hashmap

来源:互联网 发布:达梦数据库下载网盘 编辑:程序博客网 时间:2024/05/17 10:05

前几天在用stl中hash_map的时候,发现char*做为key,在比较的时候是直接==,这很蛋疼,我字符串比较你就给直接==,逗我呢。

但是可以重定义hash和compare函数来达到效果,想了想,弄一个这么难用的hash_map还要自己实现,那我还不如自己写一个得了,于是就有了下面的代码。

通过地址散列和链表冲突来实现。

头文件:

#ifndef _E_MAP_H_#define _E_MAP_H_#include "common.h"#ifdef __cplusplus  extern "C" {  #endif // 在调用了if_map_delete\if_map_clear之后,这个回调来处理value// 如果是safe状态,那么回调结束后会回收,不是safe状态,key将由你来释放内存// value的必须要你来释放内存typedef void (if_map_valueDeleteCallBack)(void *key, void* value);// 初始化一个map// capacity: -1表示自动扩容,0表示没有大小,put/get任何都会失败// safe: FALSE 表示map不会为key生成一份copy,这样key有可能会被你修改,则会出错;//       TRUE 则会为key生成一份copy,这样会导致内存稍微增大,但是key不会被修改// key在移除的时候会始终删除void* if_map_new(int capacity, BOOL safe, if_map_valueDeleteCallBack *vdcb);// 放入一个key value// return: 如果之前存在这个key,那么之前的值会返回void* if_map_put(void* map, char* key, void* value);// 得到valuevoid* if_map_get(void* map, char* key);// map的value数量int if_map_size(void* map);// 得到所有values// 配合size使用void** if_map_values(void* map);// 是否存在BOOL if_map_has(void* map, char* key);// 是否包含这个value值,简单的value == valueBOOL if_map_contain(void* map, void* value);// 通过key,移出key-valuevoid* if_map_remove(void* map, char* key);// 通过value,移出key-valuevoid* if_map_removeValue(void* map, void* value);// 移出所有key-valuevoid if_map_clear(void* map);// 释放map内存void if_map_delete(void* map);#ifdef __cplusplus  }  #endif #endif


C文件

#include "map.h"#include "util.h"// key采用取留余数法// 解决冲突采用链地址法typedef struct if_pair_struct {char *key;void *value;} ifpair;typedef struct if_node_struct {ifpair *pair;    struct if_node_struct *next;} ifnode;typedef struct if_map_struct {    BOOL safe;    int capacity;    int size;    BOOL autoExpand;    if_map_valueDeleteCallBack *valueCallback;    // node集合    ifnode **nodes;} ifmap;#define MAP_DEFAULT_SIZE 16#define EXPAND_THRESHOLD_RATE 0.75#define EXPAND_FACTOR 2// hash算法// put性能static int hash(int capacity, char* key) {    int h = 1;    char ch;    while (ch = *key++) {        h = 31 * h + ch;    }    return abs(h % capacity);}// key的比较函数// get性能static BOOL compare(char *k1, char *k2) {return if_str_cmp(k1, k2) == 0;}// 对map进行扩容static void expand(ifmap *map) {    int i;    register int preCapacity = map->capacity;    // 保存之前的node数组    register ifnode **preNodes = map->nodes;    // 扩容    map->capacity = map->capacity * EXPAND_FACTOR;    map->nodes = (ifnode**) malloc (sizeof(ifnode*) * map->capacity);    memset(map->nodes, 0, sizeof(ifnode*) * map->capacity);    // 移动node    for (i = 0; i < preCapacity; i++) {        ifnode *node = preNodes[i];        if (node) {            int hsKey = hash(map->capacity, node->pair->key);            map->nodes[hsKey] = node;        }    }free(preNodes);}// 删除pair,只会删除key,不会删除valuestatic void if_map_deletePair(ifpair *pair, BOOL safe, if_map_valueDeleteCallBack *cb) {    if (pair) {        // 只需要释放keyif (cb) {            cb(pair->key, pair->value);        }if (pair->key && safe) {free(pair->key);pair->key = 0;}        free(pair);    }}// 删除pair,只会删除key,不会删除valuestatic void if_map_deleteNode(ifnode *node, BOOL deletePair, BOOL safe, if_map_valueDeleteCallBack *cb) {    if (node) {        // 只需要释放key        if (deletePair && node->pair) {            if_map_deletePair(node->pair, safe, cb);        }        free(node);    }}// 在一个map中放入一个node// check: 是否检查是否重复的key值// 检查存在 返回之前的pairstatic ifpair* if_map_putPair(ifmap *map, ifpair *pair, BOOL check) {    int hsKey = hash(map->capacity, pair->key);    ifnode *hashNode = map->nodes[hsKey];    ifnode **ptr = NULL;    if (hashNode) {        // 存在node        // 检查元素的key值        if (check) {            if (compare(pair->key, hashNode->pair->key)) {                // 这个存在,那么替换pair                ifpair *tmpPair = hashNode->pair;                hashNode->pair = pair;                return tmpPair;            }        }        // 之前的位置上有node,那么需要循环链式遍历        while (hashNode->next) {            hashNode = hashNode->next;        }        ptr = &(hashNode->next);    } else {        // 不存在node        ptr = &(map->nodes[hsKey]);    }    {        // 构造一个新的node        ifnode *node = (ifnode*) malloc (sizeof(ifnode));        // 内存分配失败if (!node) {return NULL;}node->pair = pair;        node->next = NULL;        *ptr = node;        // 大小+1        map->size++;    }    return NULL;}// remove: 是否在得到的时候移出static ifpair* if_map_getPair(ifmap* map, char* key, BOOL remove) {    int hs = hash(map->capacity, key);    ifnode *topNode = map->nodes[hs];    ifnode *node = topNode;    ifnode *preNode = NULL;    ifpair *pair = NULL;    while (node) {        if (compare(key, node->pair->key)) {            // 找到            pair = node->pair;            break;        } else {            // 没有找到            preNode = node;            node = node->next;        }    }    if (pair && remove) {        if (node == topNode) {            // 位于散列表            map->nodes[hs] = topNode->next;        } else {            // 位于链表            preNode->next = node->next;if_map_deleteNode(node, FALSE, map->safe, NULL);        }        map->size--;    }    return pair;}// remove: 是否在得到的时候移出static ifpair* if_map_getPairValue(ifmap* map, void* value, BOOL remove) {    int i;ifpair *pair = NULL;    for (i = 0; i < map->capacity; i++) {        ifnode *topNode = map->nodes[i];        ifnode *node = topNode;        ifnode *preNode = NULL;        while (node) {            if (value == node->pair->value) {                pair = node->pair;                break;            } else {                // 没有找到                preNode = node;                node = node->next;            }        }        if (pair && remove) {            if (node == topNode) {                // 位于散列表                map->nodes[i] = topNode->next;            } else {                // 位于链表                preNode->next = node->next;if_map_deleteNode(node, FALSE, map->safe, NULL);            }            map->size--;        }if (pair) {break;}    }    return pair;}// 初始化一个map// size: -1表示自动扩容,0表示没有大小,put/get任何都会失败// safe: FALSE 表示map不会为key生成一份copy,这样key有可能会被你修改,则会出错; TRUE 则会为key生成一份copy,这样会导致内存稍微增大,但是key不会被修改void* if_map_new(int capacity, BOOL safe, if_map_valueDeleteCallBack *vdcb) {    ifmap *map = (ifmap*) malloc (sizeof(ifmap));memset(map, 0, sizeof(ifmap));    if (capacity < 0) {        // 自动扩容        map->autoExpand = TRUE;        map->size = 0;        map->capacity = MAP_DEFAULT_SIZE;    } else {        map->autoExpand = FALSE;        map->size = 0;        map->capacity = capacity;    }map->valueCallback = vdcb;    map->safe = safe;    // 分配节点指针空间    map->nodes = (ifnode**) malloc (sizeof(ifnode*) * map->capacity);    memset(map->nodes, 0, sizeof(ifnode*) * map->capacity);return map;}// 放入一个key value// return: 如果之前存在这个key,那么之前的值会返回void* if_map_put(void* m, char* key, void* value) {    ifmap *map = (ifmap*) m;    if (if_str_len(key) == 0) {        return NULL;    }    // 判断是否超过限制    if (!map->autoExpand && map->size >= map->capacity) {        return NULL;    }    // 判断是否需要扩容    if (map->autoExpand && map->size >= (map->capacity * EXPAND_THRESHOLD_RATE)) {        // 开始扩容        expand(map);    }    {        // 构造一个pair        void *ret = NULL;        ifpair *pair = (ifpair*) malloc (sizeof(ifpair));        // 为了安全        if (map->safe) {            key = if_str_clone(key);        }        pair->key = key;        pair->value = value;        pair = if_map_putPair(map, pair, TRUE);        // 之前存在相同的key的pair        if (pair) {            ret = pair->value;            if_map_deletePair(pair, map->safe, NULL);        }        return ret;    }}// 得到valuevoid* if_map_get(void* m, char* key) {    if (if_str_len(key) == 0 || !m) {        return NULL;    } else {        ifmap *map = (ifmap*) m;        void *ret = NULL;        ifpair *pair = if_map_getPair(map, key, FALSE);        if (pair) {            ret = pair->value;        }        return ret;    }}// map的value数量int if_map_size(void* m) {    if (!m) {        return -1;    } else {        ifmap *map = (ifmap*)m;        return map->size;    }}// 得到所有values// 使用完请释放内存void** if_map_values(void* m) {    if (!m) {        return NULL;    } else {        int i;        ifmap *map = (ifmap*)m;        void **ret = (void**) malloc (sizeof(void*) * map->size);int valuePtr = 0;        for (i = 0; i < map->capacity; i++) {            ifnode *node = map->nodes[i];            while (node) {                ret[valuePtr++] = node->pair->value;                node = node->next;            }        }        return ret;    }}// 是否存在BOOL if_map_has(void* m, char* key) {    if (!m) {        return FALSE;    } else {        int i;        ifmap *map = (ifmap*)m;ifnode *node = map->nodes[hash(map->capacity, key)];        while (node) {            if (compare(key, node->pair->key)) {                return TRUE;            }            node = node->next;        }        return FALSE;    }}// 是否包含这个value值,简单的value == valueBOOL if_map_contain(void* m, void* value) {    if (!m) {        return FALSE;    } else {        int i;        ifmap *map = (ifmap*)m;        for (i = 0; i < map->capacity; i++) {            ifnode *node = map->nodes[i];            while (node) {                if (value == node->pair->value) {                    return TRUE;                }                node = node->next;            }        }        return FALSE;    }}// 通过key,移出key-valuevoid* if_map_remove(void* m, char* key) {    if (if_str_len(key) == 0 || !m) {        return NULL;    } else {        ifmap *map = (ifmap*) m;        void *ret = NULL;        ifpair *pair = if_map_getPair(map, key, TRUE);        if (pair) {            ret = pair->value;            if_map_deletePair(pair, map->safe, NULL);        }        return ret;    }}// 通过value,移出key-value// 通过遍历查找,没有用value来索引void* if_map_removeValue(void* m, void* value) {    if (!m) {        return NULL;    } else {        ifmap *map = (ifmap*) m;        void *ret = NULL;        ifpair *pair = if_map_getPairValue(map, value, TRUE);if (pair) {ret = pair->value;}        return ret;    }}// 移出所有void if_map_clear(void* m) {    if (!m) {        return;    } else {int i;        ifmap *map = (ifmap*) m;// 遍历node        for (i = 0; i < map->capacity; i++) {            ifnode *node = map->nodes[i];            while (node) {ifnode *nextNode = node->next;                if_map_deleteNode(node, TRUE, map->safe, map->valueCallback);node = nextNode;            }        }memset(map->nodes, 0, sizeof(ifnode*) * map->capacity);map->size = 0;        return;    }}// 释放一个map的内存void if_map_delete(void* m) {    if (!m) {        return;    } else {int i;        ifmap *map = (ifmap*) m;        // 遍历node        for (i = 0; i < map->capacity; i++) {            ifnode *node = map->nodes[i];            while (node) {                ifnode *nextNode = node->next;                if_map_deleteNode(node, TRUE, map->safe, map->valueCallback);node = nextNode;            }        }        free(map->nodes);        free(map);    }}


完整代码地址:https://gitee.com/lastcoder/ifserver 文件夹ifclient