网上找的一个hashmap的具体实现
从网上找到hashmap截取大部分代码后运行发现一堆小问题,自己整理相关内容,进行测试显示,具体如下
此处根据实际情况会自行扩展内存,原理和java的hashmap很相似
#ifndef __PRIVATE_HASH_MAP_H__ #define __PRIVATE_HASH_MAP_H__ #ifdef __cplusplus extern "C"{ #endif #include <stdlib.h>// malloc free typedef struct entry { void * key; // 键 void * value; // 值 struct entry * next; // 冲突链表 }*Entry; #define newEntry() (Entry)malloc(sizeof(struct entry)) #define newEntryList(length) (Entry)malloc(length * sizeof(struct entry)) //#include <stdbool.h>// typedef enum __bool { false = 0,False = 0, true = 1,True=1, } bool; #include <string.h> // 哈希结构 typedef struct hashMap *HashMap; #define newHashMap() (HashMap)malloc(sizeof(struct hashMap)) // 哈希函数类型 typedef int(*HashCode)(HashMap, void * key); // 判等函数类型 typedef bool(*Equal)(void * key1, void * key2); // 添加键函数类型 typedef void(*Put)(HashMap hashMap, void * key, void * value); // 获取键对应值的函数类型 typedef void * (*Get)(HashMap hashMap, void * key); // 删除键的函数类型 typedef bool(*Remove)(HashMap hashMap, void * key); // 清空Map的函数类型 typedef void(*Clear)(HashMap hashMap); // 判断键值是否存在的函数类型 typedef bool(*Exists)(HashMap hashMap, void * key); typedef struct hashMap { int size; // 当前大小 int listSize; // 有效空间大小 HashCode hashCode; // 哈希函数 Equal equal; // 判等函数 Entry list; // 存储区域 Put put; // 添加键的函数 Get get; // 获取键对应值的函数 Remove remove; // 删除键 Clear clear; // 清空Map Exists exists; // 判断键是否存在 bool autoAssign; // 设定是否根据当前数据量动态调整内存大小,默认开启 }*HashMap; // 默认哈希函数 static int defaultHashCode(HashMap hashMap, void * key); // 默认判断键值是否相等 static bool defaultEqual(void * key1, void * key2); // 默认添加键值对 static void defaultPut(HashMap hashMap, void * key, void * value); // 默认获取键对应值 static void * defaultGet(HashMap hashMap, void * key); // 默认删除键 static bool defaultRemove(HashMap hashMap, void * key); // 默认判断键是否存在 static bool defaultExists(HashMap hashMap, void * key); // 默认清空Map static void defaultClear(HashMap hashMap); // 创建一个哈希结构 HashMap createHashMap(HashCode hashCode, Equal equal); // 重新构建 static void resetHashMap(HashMap hashMap, int listSize); // 迭代器结构 typedef struct hashMapIterator { Entry entry; // 迭代器当前指向 int count; // 迭代次数 int hashCode; // 键值对的哈希值 HashMap hashMap; }*HashMapIterator; #define newHashMapIterator() (HashMapIterator)malloc(sizeof(struct hashMapIterator)) // 创建一个哈希结构 HashMap createHashMap(HashCode hashCode, Equal equal); // 创建哈希结构迭代器 HashMapIterator createHashMapIterator(HashMap hashMap); // 迭代器是否有下一个 bool hasNextHashMapIterator(HashMapIterator iterator); // 迭代到下一次 HashMapIterator nextHashMapIterator(HashMapIterator iterator); // 释放迭代器内存 void freeHashMapIterator(HashMapIterator * iterator); #ifdef __cplusplus } #endif #endif /* //编译 gcc -o t04_testhasnmap main.c hashmap.c #include "hashmap.h" #include <stdio.h> #define HashMapPut(map, key, value) map->put(map, (void *)key, (void *)value); #define HashMapGet(map, key) (char *)map->get(map, (void *)key) #define HashMapRemove(map, key) map->remove(map, (void *)key) #define HashMapExists(map, key) map->exists(map, (void *)key) int main() { HashMap map = createHashMap(NULL, NULL); HashMapPut(map, "asdfasdf", "asdfasdfds"); HashMapPut(map, "sasdasd", "asdfasdfds"); HashMapPut(map, "asdhfgh", "asdfasdfds"); HashMapPut(map, "4545", "asdfasdfds"); HashMapPut(map, "asdfaasdasdsdf", "asdfasdfds"); HashMapPut(map, "asdasg", "asdfasdfds"); HashMapPut(map, "qweqeqwe", "asdfasdfds"); printf("key: 4545, exists: %s\n", HashMapExists(map, "4545") ? "true" : "false"); printf("4545: %s\n", HashMapGet(map, "4545")); printf("remove 4545 %s\n", HashMapRemove(map, "4545") ? "true" : "false"); printf("remove 4545 %s\n", HashMapRemove(map, "4545") ? "true" : "false"); printf("key: 4545, exists: %s\n", HashMapExists(map, "4545") ? "true" : "false"); HashMapIterator iterator = createHashMapIterator(map); while (hasNextHashMapIterator(iterator)) { iterator = nextHashMapIterator(iterator); printf("{ key: %s, value: %s, hashcode: %d }\n", (char *)iterator->entry->key, (char *)iterator->entry->value, iterator->hashCode); } map->clear(map); freeHashMapIterator(&iterator); return 0; } */ /* 常见的hash算法 参考 https://blog.csdn.net/yanshu2012/article/details/50594218 推荐使用 BKDRHash unsigned int SDBMHash(char *str) { unsigned int hash = 0; while (*str) { // equivalent to: hash = 65599*hash + (*str++); hash = (*str++) + (hash << 6) + (hash << 16) - hash; } return (hash & 0x7FFFFFFF); } // RS Hash Function unsigned int RSHash(char *str) { unsigned int b = 378551; unsigned int a = 63689; unsigned int hash = 0; while (*str) { hash = hash * a + (*str++); a *= b; } return (hash & 0x7FFFFFFF); } // JS Hash Function unsigned int JSHash(char *str) { unsigned int hash = 1315423911; while (*str) { hash ^= ((hash << 5) + (*str++) + (hash >> 2)); } return (hash & 0x7FFFFFFF); } // P. J. Weinberger Hash Function unsigned int PJWHash(char *str) { unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8); unsigned int ThreeQuarters = (unsigned int)((BitsInUnignedInt * 3) / 4); unsigned int OneEighth = (unsigned int)(BitsInUnignedInt / 8); unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth); unsigned int hash = 0; unsigned int test = 0; while (*str) { hash = (hash << OneEighth) + (*str++); if ((test = hash & HighBits) != 0) { hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits)); } } return (hash & 0x7FFFFFFF); } // ELF Hash Function unsigned int ELFHash(char *str) { unsigned int hash = 0; unsigned int x = 0; while (*str) { hash = (hash << 4) + (*str++); if ((x = hash & 0xF0000000L) != 0) { hash ^= (x >> 24); hash &= ~x; } } return (hash & 0x7FFFFFFF); } // BKDR Hash Function unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); } // DJB Hash Function unsigned int DJBHash(char *str) { unsigned int hash = 5381; while (*str) { hash += (hash << 5) + (*str++); } return (hash & 0x7FFFFFFF); } // AP Hash Function unsigned int APHash(char *str) { unsigned int hash = 0; int i; for (i=0; *str; i++) { if ((i & 1) == 0) { hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); } else { hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); } } return (hash & 0x7FFFFFFF); } */
#include "hashmap.h" int defaultHashCode(HashMap hashMap, void * key) { char* k = (char*)key; unsigned long h = 0; while (*k) { h = (h << 4) + *k++; unsigned long g = h & 0xF0000000L; if (g) { h ^= g >> 24; } h &= ~g; } return h % hashMap->listSize; } bool defaultEqual(void * key1, void * key2){ if(strcmp(key1,key2)==0){return true;} else{return false;} } void resetHashMap(HashMap hashMap, int listSize) { if (listSize < 8) return; // 键值对临时存储空间 Entry tempList = newEntryList(hashMap->size); HashMapIterator iterator = createHashMapIterator(hashMap); int length = hashMap->size; for (int index = 0; hasNextHashMapIterator(iterator); index++) { // 迭代取出所有键值对 iterator = nextHashMapIterator(iterator); tempList[index].key = iterator->entry->key; tempList[index].value = iterator->entry->value; tempList[index].next = NULL; } freeHashMapIterator(&iterator); // 清除原有键值对数据 hashMap->size = 0; for (int i = 0; i < hashMap->listSize; i++) { Entry current = &hashMap->list[i]; current->key = NULL; current->value = NULL; if (current->next != NULL) { while (current->next != NULL) { Entry temp = current->next->next; free(current->next); current->next = temp; } } } // 更改内存大小 hashMap->listSize = listSize; Entry relist = (Entry)realloc(hashMap->list, hashMap->listSize * sizeof(struct entry)); if (relist != NULL) { hashMap->list = relist; relist = NULL; } // 初始化数据 for (int i = 0; i < hashMap->listSize; i++) { hashMap->list[i].key = NULL; hashMap->list[i].value = NULL; hashMap->list[i].next = NULL; } // 将所有键值对重新写入内存 for (int i = 0; i < length; i++) { hashMap->put(hashMap, tempList[i].key, tempList[i].value); } free(tempList); } void defaultPut(HashMap hashMap, void* key, void* value) { if (hashMap->autoAssign && hashMap->size >= hashMap->listSize) { // 内存扩充至原来的两倍 // *注: 扩充时考虑的是当前存储元素数量与存储空间的大小关系,而不是存储空间是否已经存满, // 例如: 存储空间为10,存入了10个键值对,但是全部冲突了,所以存储空间空着9个,其余的全部挂在一个上面, // 这样检索的时候和遍历查询没有什么区别了,可以简单这样理解,当我存入第11个键值对的时候一定会发生冲突, // 这是由哈希函数本身的特性(取模)决定的,冲突就会导致检索变慢,所以这时候扩充存储空间,对原有键值对进行 // 再次散列,会把冲突的数据再次分散开,加快索引定位速度。 resetHashMap(hashMap, hashMap->listSize * 2); } int index = hashMap->hashCode(hashMap, key); if (hashMap->list[index].key == NULL) { hashMap->size++; // 该地址为空时直接存储 hashMap->list[index].key = key; hashMap->list[index].value = value; } else { Entry current = &hashMap->list[index]; while (current != NULL) { if (hashMap->equal(key, current->key)) { // 对于键值已经存在的直接覆盖 current->value = value; return; } current = current->next; }; // 发生冲突则创建节点挂到相应位置的next上 Entry entry = newEntry(); entry->key = key; entry->value = value; entry->next = hashMap->list[index].next; hashMap->list[index].next = entry; hashMap->size++; } } void* defaultGet(HashMap hashMap, void* key) { int index = hashMap->hashCode(hashMap, key); Entry entry = &hashMap->list[index]; while (entry->key != NULL && !hashMap->equal(entry->key, key)) { entry = entry->next; } return entry->value; } bool defaultRemove(HashMap hashMap, void* key) { int index = hashMap->hashCode(hashMap, key); Entry entry = &hashMap->list[index]; if (entry->key == NULL) { return False; } bool result = False; if (hashMap->equal(entry->key, key)) { hashMap->size--; if (entry->next != NULL) { Entry temp = entry->next; entry->key = temp->key; entry->value = temp->value; entry->next = temp->next; free(temp); } else { entry->key = entry->value = NULL; } result = True; } else { Entry p = entry; entry = entry->next; while (entry != NULL) { if (hashMap->equal(entry->key, key)) { hashMap->size--; p->next = entry->next; free(entry); result = True; break; } p = entry; entry = entry->next; }; } // 如果空间占用不足一半,则释放多余内存 if (result && hashMap->autoAssign && hashMap->size < hashMap->listSize / 2) { resetHashMap(hashMap, hashMap->listSize / 2); } return result; } bool defaultExists(HashMap hashMap, void* key) { int index = hashMap->hashCode(hashMap, key); Entry entry = &hashMap->list[index]; if (entry->key == NULL) { return False; } if (hashMap->equal(entry->key, key)) { return True; } if (entry->next != NULL) { do { if (hashMap->equal(entry->key, key)) { return True; } entry = entry->next; } while (entry != NULL); return False; } else { return False; } } void defaultClear(HashMap hashMap) { for (int i = 0; i < hashMap->listSize; i++) { // 释放冲突值内存 Entry entry = hashMap->list[i].next; while (entry != NULL) { Entry next = entry->next; free(entry); entry = next; } hashMap->list[i].next = NULL; } // 释放存储空间 free(hashMap->list); hashMap->list = NULL; hashMap->size = -1; hashMap->listSize = 0; } HashMap createHashMap(HashCode hashCode, Equal equal) { HashMap hashMap = newHashMap(); hashMap->size = 0; hashMap->listSize = 8; hashMap->hashCode = hashCode == NULL ? defaultHashCode : hashCode; hashMap->equal = equal == NULL ? defaultEqual : equal; hashMap->exists = defaultExists; hashMap->get = defaultGet; hashMap->put = defaultPut; hashMap->remove = defaultRemove; hashMap->clear = defaultClear; hashMap->autoAssign = True; // 起始分配8个内存空间,溢出时会自动扩充 hashMap->list = newEntryList(hashMap->listSize); Entry p = hashMap->list; for (int i = 0; i < hashMap->listSize; i++) { p[i].key = p[i].value = p[i].next = NULL; } return hashMap; } HashMapIterator createHashMapIterator(HashMap hashMap) { HashMapIterator iterator = newHashMapIterator(); iterator->hashMap = hashMap; iterator->count = 0; iterator->hashCode = -1; iterator->entry = NULL; return iterator; } bool hasNextHashMapIterator(HashMapIterator iterator) { return iterator->count < iterator->hashMap->size ? True : False; } HashMapIterator nextHashMapIterator(HashMapIterator iterator) { if (hasNextHashMapIterator(iterator)) { if (iterator->entry != NULL && iterator->entry->next != NULL) { iterator->count++; iterator->entry = iterator->entry->next; return iterator; } while (++iterator->hashCode < iterator->hashMap->listSize) { Entry entry = &iterator->hashMap->list[iterator->hashCode]; if (entry->key != NULL) { iterator->count++; iterator->entry = entry; break; } } } return iterator; } void freeHashMapIterator(HashMapIterator * iterator) { free(*iterator); *iterator = NULL; }
建议,首次直接将链表开到实际需要的大小,避免后期扩张,
初始化容量的大小保持2的幂次方
//