C语言hashmap

前几天在用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);
// 得到value
void* 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 == value
BOOL if_map_contain(void* map, void* value);
// 通过key,移出key-value
void* if_map_remove(void* map, char* key);
// 通过value,移出key-value
void* if_map_removeValue(void* map, void* value);
// 移出所有key-value
void 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,不会删除value
static void if_map_deletePair(ifpair *pair, BOOL safe, if_map_valueDeleteCallBack *cb) {
    if (pair) {
        // 只需要释放key
		if (cb) {
            cb(pair->key, pair->value);
        }
		if (pair->key && safe) {
			free(pair->key);
			pair->key = 0;
		}
        free(pair);
    }
}

// 删除pair,只会删除key,不会删除value
static 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值
// 检查存在 返回之前的pair
static 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;
    }
}

// 得到value
void* 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 == value
BOOL 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-value
void* 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


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值