PracticeDev/study_cpp/hashmap_test/hashmap_test.cpp

419 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 定义键值对结构
typedef struct entry {
void * key; // 键
void * value; // 值
struct entry * next; // 冲突链表
}*Entry;
#define newEntry() NEW(struct entry)
#define newEntryList(length) (Entry)malloc(length * sizeof(struct entry))\
// start HashMap结构体
// 哈希结构
typedef struct hashMap *HashMap;
#define newHashMap() NEW(struct hashMap)
// 哈希函数类型
typedef int(*HashCode)(HashMap, void * key);
// 判等函数类型
typedef Boolean(*Equal)(void * key1, void * key2);
// 添加键函数类型
typedef void(*Put)(HashMap hashMap, void * key, void * value);
// 获取键对应值的函数类型
typedef void * (*Get)(HashMap hashMap, void * key);
// 删除键的函数类型
typedef Boolean(*Remove)(HashMap hashMap, void * key);
// 清空Map的函数类型
typedef void(*Clear)(HashMap hashMap);
// 判断键值是否存在的函数类型
typedef Boolean(*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; // 判断键是否存在
Boolean autoAssign; // 设定是否根据当前数据量动态调整内存大小,默认开启
}*HashMap;
// // 默认哈希函数
// static int defaultHashCode(HashMap hashMap, void * key);
// // 默认判断键值是否相等
// static Boolean defaultEqual(void * key1, void * key2);
// // 默认添加键值对
// static void defaultPut(HashMap hashMap, void * key, void * value);
// // 默认获取键对应值
// static void * defaultGet(HashMap hashMap, void * key);
// // 默认删除键
// static Boolean defaultRemove(HashMap hashMap, void * key);
// // 默认判断键是否存在
// static Boolean defaultExists(HashMap hashMap, void * key);
// // 默认清空Map
// static void defaultClear(HashMap hashMap);
// // 创建一个哈希结构
// HashMap createHashMap(HashCode hashCode, Equal equal);
// // 重新构建
// static void resetHashMap(HashMap hashMap, int listSize);
// end HashMap结构体
// 哈希函数
int defaultHashCode(HashMap hashMap, let key)
{
IN_STACK;
string k = (string)key;
unsigned long h = 0;
while (*k) {
h = (h << 4) + *k++;
unsigned long g = h & 0xF0000000L;
if (g) {
h ^= g >> 24;
}
h &= ~g;
}
OUT_STACK;
return h % hashMap->listSize;
}
//put函数 用于在哈希表中存入一个键值对
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++) {
Array x = tempList[i].value;
hashMap->put(hashMap, tempList[i].key, tempList[i].value);
}
free(tempList);
}
void defaultPut(HashMap hashMap, let key, let 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++;
// 该地址为空时直接存储
Array x = value;
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++;
}
}
//其它函数
let defaultGet(HashMap hashMap, let 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;
}
Boolean defaultRemove(HashMap hashMap, let key) {
int index = hashMap->hashCode(hashMap, key);
Entry entry = &hashMap->list[index];
if (entry->key == NULL) {
return False;
}
Boolean 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;
}
Boolean defaultExists(HashMap hashMap, let 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;
}
// Iterator接口提供了遍历HashMap结构的方法
// 迭代器结构
typedef struct hashMapIterator {
Entry entry; // 迭代器当前指向
int count; // 迭代次数
int hashCode; // 键值对的哈希值
HashMap hashMap;
}*HashMapIterator;
#define newHashMapIterator() NEW(struct hashMapIterator)
// // 创建一个哈希结构
// HashMap createHashMap(HashCode hashCode, Equal equal);
// // 创建哈希结构迭代器
// HashMapIterator createHashMapIterator(HashMap hashMap);
// // 迭代器是否有下一个
// Boolean hasNextHashMapIterator(HashMapIterator iterator);
// // 迭代到下一次
// HashMapIterator nextHashMapIterator(HashMapIterator iterator);
// // 释放迭代器内存
// void freeHashMapIterator(HashMapIterator * iterator);
// 实现
HashMapIterator createHashMapIterator(HashMap hashMap) {
HashMapIterator iterator = newHashMapIterator();
iterator->hashMap = hashMap;
iterator->count = 0;
iterator->hashCode = -1;
iterator->entry = NULL;
return iterator;
}
Boolean 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;
}
#define Put(map, key, value) map->put(map, (void *)key, (void *)value);
#define Get(map, key) (char *)map->get(map, (void *)key)
#define Remove(map, key) map->remove(map, (void *)key)
#define Existe(map, key) map->exists(map, (void *)key)
int main() {
HashMap map = createHashMap(NULL, NULL);
Put(map, "asdfasdf", "asdfasdfds");
Put(map, "sasdasd", "asdfasdfds");
Put(map, "asdhfgh", "asdfasdfds");
Put(map, "4545", "asdfasdfds");
Put(map, "asdfaasdasdsdf", "asdfasdfds");
Put(map, "asdasg", "asdfasdfds");
Put(map, "qweqeqwe", "asdfasdfds");
printf("key: 4545, exists: %s\n", Existe(map, "4545") ? "true" : "false");
printf("4545: %s\n", Get(map, "4545"));
printf("remove 4545 %s\n", Remove(map, "4545") ? "true" : "false");
printf("remove 4545 %s\n", Remove(map, "4545") ? "true" : "false");
printf("key: 4545, exists: %s\n", Existe(map, "4545") ? "true" : "false");
HashMapIterator iterator = createHashMapIterator(map);
while (hasNextHashMapIterator(iterator)) {
iterator = nextHashMapIterator(iterator);
printf("{ key: %s, key: %s, hashcode: %d }\n",
(char *)iterator->entry->key, (char *)iterator->entry->value, iterator->hashCode);
}
map->clear(map);
freeHashMapIterator(&iterator);
return 0;
}