C language implements and validates the hash table
This commit is contained in:
parent
a1df906d16
commit
3aea5d919e
Binary file not shown.
Before Width: | Height: | Size: 75 KiB |
Binary file not shown.
Before Width: | Height: | Size: 102 KiB |
|
@ -1,58 +1,78 @@
|
||||||
# 基于cortex-m3-emulator实现哈希表并测试验证##
|
# 基于cortex-m3-emulator实现哈希表并测试验证##
|
||||||
|
|
||||||
## 1. 简介
|
## 1. 简介
|
||||||
利用c语言实现了哈希表(HashMap),包括添加键值对(Put),获取键对应的值(Get), 删除健(Delete),清空哈希表(Clear), 迭代遍历哈希表(hashMapIterator)等功能
|
使用c语言实现hash表,实现hash表的基本操作,包括查找、删除、插入等。
|
||||||
操作。
|
使用链表法来解决hash冲突的问题,链表为双向链表。
|
||||||
|
hash函数使用murmurhash2。
|
||||||
|
哈希表初始的大小为16,当装载因子大于0.7时会进行2倍扩容。
|
||||||
|
|
||||||
利用数组(Entry)作为存储空间,利用链表(*next)解决冲突。当哈希表的大小超过数组大小后,为避免发生冲突过多的情况,可以对哈希表扩容。
|
定义结构体来存储键值对。
|
||||||
|
|
||||||
## 2. 数据结构设计说明
|
## 2. 数据结构设计说明
|
||||||
键值对结构
|
键值对结构体,使用void *指针存储键和值。使用双向链表构建冲突链表。
|
||||||
typedef struct entry {
|
```
|
||||||
void * key; // 键
|
tyepdef struct hashNode{
|
||||||
void * value; // 值
|
const void * key;
|
||||||
struct entry * next; // 冲突链表
|
const void * value;
|
||||||
}*Entry;
|
entry * pre;
|
||||||
|
entry * next;
|
||||||
哈希结构
|
}*entry;
|
||||||
typedef struct hashMap {
|
```
|
||||||
int size; // 当前大小
|
---------
|
||||||
int listSize; // 有效空间大小
|
哈希表结构体
|
||||||
HashCode hashCode; // 哈希函数
|
```
|
||||||
Equal equal; // 判等函数
|
typedef struct hashmap
|
||||||
Entry list; // 存储区域
|
{
|
||||||
Put put; // 添加键的函数
|
entry *entryList; // 键值对 头结点数组
|
||||||
Get get; // 获取键对应值的函数
|
unsigned int size; // hash表中的有效元素个数
|
||||||
Remove remove; // 删除键
|
unsigned int len; // 数组的大小
|
||||||
Clear clear; // 清空Map
|
float factor; // 装载因子
|
||||||
Exists exists; // 判断键是否存在
|
unsigned int (*hash)(const void *, unsigned __int64, hashmap *);//哈希函数
|
||||||
Boolean autoAssign; // 设定是否根据当前数据量动态调整内存大小,默认开启
|
const void *(*get)(const void *, hashmap *); // 获得元素
|
||||||
}*HashMap;
|
void (*push)(const void *, const void *, hashmap *); // 插入元素
|
||||||
|
void (*clear)(hashmap *); // 清空整个hash表
|
||||||
包括以下函数功能,分别为:
|
int (*isEmpty)(hashmap *); // 检查hash表是否为空
|
||||||
`createHashMap`:创建一个哈希结构
|
void (*del)(const void *, hashmap *); // 删除元素
|
||||||
`defaultPut`:添加键值对
|
int (*keyEqual)(const void *, const void *); // 检查key值是否相同
|
||||||
`defaultGet`:获取键对应值
|
} *HashMap;
|
||||||
`defaultRemove`:删除指定键的键值对
|
```
|
||||||
`defaultExists`:判断键值是否存在
|
|
||||||
`defaultClear`:清空Map的函数类型
|
|
||||||
`resetHashMap`:重新构建哈希表
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
遍历用的结构体(迭代器)
|
||||||
|
```
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
HashMap map; //哈希表指针
|
||||||
|
Entry cur; // 当前指针
|
||||||
|
unsigned int count; // 计数
|
||||||
|
unsigned int index; // 索引
|
||||||
|
int (*hasNext)(Iterator iter);//是否有下一个元素
|
||||||
|
Entry *(*next)(Iterator iter);//获取下一个键值对
|
||||||
|
void (*destroy)(Iterator iter);//销毁迭代器
|
||||||
|
};
|
||||||
|
```
|
||||||
## 3. 测试程序说明
|
## 3. 测试程序说明
|
||||||
测试了哈希表的插入键值对(Put),判断键是否存在(Exist),获取键对应的值(Get), 删除健(Delete),迭代遍历哈希表(hashMapIterator),清空哈希表(Clear)等操作。
|
测试了哈希表的插入键值对(push),迭代遍历哈希表并打印等操作。
|
||||||
并展示了利用链地址法解决哈希冲突的示例, 两个不同的人(Bob和Li Ming)的hashcode相同。
|
|
||||||
|
|
||||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
|
## 4. 运行结果
|
||||||
|
打开menuconfig之后,将test_hash开启(y),保存后退出
|
||||||

|

|
||||||
打开menuconfig之后,将test_hash_map开启(y),保存后退出
|
|
||||||
|
|
||||||

|
|
||||||
编译XiZi-cortex-m3-emulator.elf成功
|
编译XiZi-cortex-m3-emulator.elf成功
|
||||||
|

|
||||||
|
|
||||||

|
|
||||||
启动qemu模拟Xiuos操作系统,验证TestHash注册Shell命令
|
启动qemu模拟Xiuos操作系统,验证TestHash注册Shell命令
|
||||||
|
(qemu-system-arm -M lm3s6965evb -nographic -kernel build/XiZi-cortex-m3-emulator.elf)
|
||||||
|

|
||||||
|
|
||||||

|
执行ShowHash命令,打印测试结果。
|
||||||
执行TestHash命令,打印测试结果。
|

|
||||||
|
|
||||||
|
执行HashGet命令,打印测试结果。
|
||||||
|

|
||||||
|
|
||||||
|
执行HashPut命令,打印测试结果。
|
||||||
|

|
||||||
|
|
||||||
|
执行HashDelete命令,打印测试结果。
|
||||||
|

|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
Binary file not shown.
Before Width: | Height: | Size: 95 KiB |
|
@ -1,323 +1,81 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file: test_hash.c
|
* @file test_hash.c
|
||||||
* @brief: a application of test hash function
|
* @author zhangchongke (senorisky@126.com)
|
||||||
* @version: 3.0
|
* @brief C language to implement the hash table
|
||||||
* @author: Yao wenying
|
* @version 0.1
|
||||||
* @date: 2023/05/26
|
* @date 2023-09-17
|
||||||
*/
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <transform.h>
|
#include <transform.h>
|
||||||
#include"test_hash.h"
|
#include "test_hash.h"
|
||||||
|
HashMapType CreateDefaultHashMap() {
|
||||||
int defaultHashCode(HashMap hashMap, let key) {
|
HashMapType map = CreateHashMap();
|
||||||
char * k = (char *)key;
|
map->Push("1", "dhu", map);
|
||||||
unsigned long h = 0;
|
map->Push("2", "edu", map);
|
||||||
while (*k) {
|
map->Push("3", "cn", map);
|
||||||
h = (h << 4) + *k++;
|
map->Push("4", "YES", map);
|
||||||
unsigned long g = h & 0xF0000000L;
|
map->Push("5", "Welcome", map);
|
||||||
if (g) {
|
map->Push("6", "Congradualation", map);
|
||||||
h ^= g >> 24;
|
return map;
|
||||||
}
|
|
||||||
h &= ~g;
|
|
||||||
}
|
|
||||||
return h % hashMap->listSize;
|
|
||||||
}
|
}
|
||||||
|
void Show(HashMapType map) {
|
||||||
Boolean defaultEqual(let key1, let key2) {
|
printf("key\t\t\tvalue\t\thashValue\n");
|
||||||
return strcmp((string)key1, (string)key2) ? False : True;
|
Iterator iter = GetIterator(map);
|
||||||
}
|
HashNodeType node = NULL;
|
||||||
|
while (iter->HashNext(iter)) {
|
||||||
void resetHashMap(HashMap hashMap, int listSize) {
|
node = iter->Next(iter);
|
||||||
|
printf("%s\t\t\t%s\t\t\t%d\n", (char*)node->key, (char*)node->value, map->Hash(node->key, strlen(node->key), map));
|
||||||
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, let key, let value) {
|
|
||||||
// 获取哈希值
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hashMap->autoAssign && hashMap->size >= hashMap->listSize) {
|
|
||||||
|
|
||||||
// 内存扩充至原来的两倍
|
|
||||||
// *注: 扩充时考虑的是当前存储元素数量与存储空间的大小关系,而不是存储空间是否已经存满,
|
|
||||||
// 例如: 存储空间为10,存入了10个键值对,但是全部冲突了,所以存储空间空着9个,其余的全部挂在一个上面,
|
|
||||||
// 这样检索的时候和遍历查询没有什么区别了,可以简单这样理解,当我存入第11个键值对的时候一定会发生冲突,
|
|
||||||
// 这是由哈希函数本身的特性(取模)决定的,冲突就会导致检索变慢,所以这时候扩充存储空间,对原有键值对进行
|
|
||||||
// 再次散列,会把冲突的数据再次分散开,加快索引定位速度。
|
|
||||||
resetHashMap(hashMap, hashMap->listSize * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultGet(HashMap hashMap, let key) {
|
|
||||||
if (hashMap->exists(hashMap, key)) {
|
|
||||||
int index = hashMap->hashCode(hashMap, key);
|
|
||||||
Entry entry = &hashMap->list[index];
|
|
||||||
while (entry != NULL) {
|
|
||||||
if (hashMap->equal(entry->key, key)) {
|
|
||||||
return entry->value;
|
|
||||||
}
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultRemove(HashMap hashMap, let key) {
|
|
||||||
int index = hashMap->hashCode(hashMap, key);
|
|
||||||
Entry entry = &hashMap->list[index];
|
|
||||||
if (entry->key == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
let entryKey = entry->key;
|
|
||||||
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 = NULL;
|
|
||||||
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 entryKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean defaultExists(HashMap hashMap, let key) {
|
|
||||||
int index = hashMap->hashCode(hashMap, key);
|
|
||||||
Entry entry = &hashMap->list[index];
|
|
||||||
if (entry->key == NULL) {
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
while (entry != NULL) {
|
|
||||||
if (hashMap->equal(entry->key, key)) {
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
if (hashMap == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
if (hashMap->list == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
if (iterator == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
|
|
||||||
void TestHash() {
|
|
||||||
HashMap map = createHashMap(NULL, NULL);
|
|
||||||
Put(map, "000123", "Annie");
|
|
||||||
Put(map, "000245", "Bob");
|
|
||||||
Put(map, "000284", "Daniel");
|
|
||||||
Put(map, "000281", "Luna");
|
|
||||||
Put(map, "000587", "Yao");
|
|
||||||
Put(map, "000985", "Li Ming");
|
|
||||||
Put(map, "000852", "Janne");
|
|
||||||
|
|
||||||
printf("print the key-values in hashmap:\n");
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
printf("key: 000852, exists: %s\n", Existe(map, "000852") ? "true" : "false");
|
|
||||||
printf("000852: %s\n", Get(map, "000852"));
|
|
||||||
printf("remove 000852 %s\n", Remove(map, "000852") ? "true" : "false");
|
|
||||||
printf("key: 000852, exists: %s\n", Existe(map, "000852") ? "true" : "false");
|
|
||||||
|
|
||||||
map->clear(map);
|
|
||||||
freeHashMapIterator(&iterator);
|
|
||||||
}
|
}
|
||||||
|
void ShowHash() {
|
||||||
|
HashMapType map = CreateDefaultHashMap();
|
||||||
|
printf("all the operations are based on the default hash_map bellow\nall the operations will just change the map temporarily\n");
|
||||||
|
printf("show all the elements in the default hash_map with iterator\n");
|
||||||
|
Show(map);
|
||||||
|
}
|
||||||
|
void HashPut(int args, char* arg1[]) {
|
||||||
|
if (args != 3) {
|
||||||
|
printf("you can only put one key-value once a time\n");
|
||||||
|
}
|
||||||
|
HashMapType map = CreateDefaultHashMap();
|
||||||
|
map->Push(arg1[1], arg1[2], map);
|
||||||
|
Show(map);
|
||||||
|
}
|
||||||
|
void HashDelete(int args, char* arg1[]) {
|
||||||
|
if (args != 2) {
|
||||||
|
printf("you can only delete one element once a time\n");
|
||||||
|
}
|
||||||
|
HashMapType map = CreateDefaultHashMap();
|
||||||
|
map->Del(arg1[1], map);
|
||||||
|
Show(map);
|
||||||
|
}
|
||||||
|
void HashClear() {
|
||||||
|
HashMapType map = CreateDefaultHashMap();
|
||||||
|
map->Clear(map);
|
||||||
|
Show(map);
|
||||||
|
}
|
||||||
|
void HashGet(int args, char* arg1[]) {
|
||||||
|
if (args != 2) {
|
||||||
|
printf("you can only get one element once a time\n");
|
||||||
|
}
|
||||||
|
HashMapType map = CreateDefaultHashMap();
|
||||||
|
const char* value = map->Get(arg1[1], map);
|
||||||
|
printf("%s", arg1[1]);
|
||||||
|
if (value == NULL) {
|
||||||
|
printf("there is no key called %s\n", (char*)arg1[1]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unsigned int len = strlen(arg1[1]);
|
||||||
|
unsigned int hash = map->Hash(arg1[1], len, map);
|
||||||
|
printf("the value is %s\nthe hash of value is %d\n", value, hash);
|
||||||
|
}
|
||||||
|
|
||||||
PRIV_SHELL_CMD_FUNCTION(TestHash, Implement hash_map, PRIV_SHELL_CMD_MAIN_ATTR);
|
}
|
||||||
|
PRIV_SHELL_CMD_FUNCTION(ShowHash, show default hash_map, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||||
|
PRIV_SHELL_CMD_FUNCTION(HashGet, test hash_get, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||||
|
PRIV_SHELL_CMD_FUNCTION(HashClear, test hash_clear, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||||
|
PRIV_SHELL_CMD_FUNCTION(HashDelete, test hash_delete, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||||
|
PRIV_SHELL_CMD_FUNCTION(HashPut, test hash_put, PRIV_SHELL_CMD_MAIN_ATTR);
|
|
@ -1,129 +1,313 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file: test_hash.h
|
* @file test_hash.h
|
||||||
* @brief: a application of test hash function
|
* @author zhangchongke (senorisky@126.com)
|
||||||
* @version: 3.0
|
* @brief C language to implement the hash table
|
||||||
* @author: Yao wenying
|
* @version 0.1
|
||||||
* @date: 2023/05/26
|
* @date 2023-09-17
|
||||||
*/
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define BASE 16 // 初始hash表大小
|
||||||
|
|
||||||
#ifndef __HASHMAP_H__
|
typedef struct HashNode {
|
||||||
#define __HASHMAP_H__
|
const void* value; // 值
|
||||||
|
const void* key; // 键
|
||||||
|
struct HashNode* next;
|
||||||
|
struct HashNode* pre; // 双向链表指针
|
||||||
|
} *HashNodeType;
|
||||||
|
|
||||||
#include<stdlib.h>
|
typedef struct HashMap {
|
||||||
#include<string.h>
|
HashNodeType* entry_list; // 键值对 头结点数组
|
||||||
#include<stdio.h>
|
unsigned int size; // hash表中的有效元素个数
|
||||||
|
unsigned int len; // 数组的大小
|
||||||
|
float factor; // 装载因子
|
||||||
|
unsigned int (*Hash)(const void*, unsigned int len, struct HashMap*);
|
||||||
|
const void* (*Get)(const void*, struct HashMap*); // 获得元素
|
||||||
|
void (*Push)(const void*, const void*, struct HashMap*); // 插入元素
|
||||||
|
void (*Clear)(struct HashMap*); // 清空整个hash表
|
||||||
|
int (*IsEmpty)(struct HashMap*); // 检查hash表是否为空
|
||||||
|
void (*Del)(const void*, struct HashMap*); // 删除元素
|
||||||
|
int (*KeyEqual)(const void*, const void*); // 检查key值是否相同
|
||||||
|
} *HashMapType;
|
||||||
|
|
||||||
|
typedef struct Iter {
|
||||||
|
/* data */
|
||||||
|
HashMapType map;
|
||||||
|
HashNodeType cur; // 当前指针
|
||||||
|
unsigned int count; // 计数
|
||||||
|
unsigned int index; // 索引
|
||||||
|
int (*HashNext)(struct Iter* iter); // 是否有下一个元素
|
||||||
|
HashNodeType(*Next)(struct Iter* iter); // 获取下一个键值对
|
||||||
|
void (*Destroy)(struct Iter* iter); // 销毁迭代器
|
||||||
|
} *Iterator;
|
||||||
|
|
||||||
// 实现数据的基本类型
|
int IsEmpty(HashMapType map);
|
||||||
// 字符串类型
|
int HasNext(Iterator iter);
|
||||||
#define string char *
|
unsigned int Hash(const void* key, unsigned int len, HashMapType map);
|
||||||
#define newString(str) strcpy((char *)malloc(strlen(str) + 1), str)
|
int KeyEqual(const void* innerKey, const void* outerKey);
|
||||||
#define NEW(type) (type *)malloc(sizeof(type))
|
Iterator GetIterator(HashMapType map);
|
||||||
|
HashNodeType Next(Iterator iter);
|
||||||
|
const void* Get(const void* key, HashMapType map);
|
||||||
|
void Push(const void* key, const void* value, HashMapType map);
|
||||||
|
void Clear(HashMapType map);
|
||||||
|
void Del(const void* key, HashMapType map);
|
||||||
|
void IniteHashNodeTypeList(HashNodeType* list, unsigned int len);
|
||||||
|
void Destroy(struct Iter* iter);
|
||||||
|
|
||||||
// 布尔类型
|
int IsEmpty(HashMapType map) {
|
||||||
enum _Boolean { True = 1, False = 0 };
|
return map->size == 0;
|
||||||
typedef enum _Boolean Boolean;
|
}
|
||||||
|
int HasNext(Iterator iter) {
|
||||||
|
|
||||||
#define let void *
|
if (iter->count == iter->map->size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int KeyEqual(const void* innerKey, const void* outerKey) {
|
||||||
|
if (innerKey == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return !strcmp((const char*)innerKey, (const char*)outerKey);
|
||||||
|
}
|
||||||
|
void IniteHashNodeTypeList(HashNodeType* list, unsigned int len) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < len) {
|
||||||
|
HashNodeType p = (HashNodeType)malloc(sizeof(struct HashNode));
|
||||||
|
p->next = NULL;
|
||||||
|
p->key = NULL;
|
||||||
|
p->value = NULL;
|
||||||
|
list[i] = p;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct entry {
|
// 使用murmur_hash2
|
||||||
let key; // 键
|
unsigned int Hash(const void* key, unsigned int len, HashMapType map) {
|
||||||
let value; // 值
|
const unsigned int m = 0x5bd1e995;
|
||||||
struct entry * next; // 冲突链表
|
unsigned int h, k;
|
||||||
}*Entry;
|
h = 0 ^ len;
|
||||||
|
const unsigned char* data = (const unsigned char*)key;
|
||||||
|
while (len >= 4 && *data) {
|
||||||
|
k = *(unsigned int*)data;
|
||||||
|
|
||||||
#define newEntry() NEW(struct entry)
|
k *= m;
|
||||||
#define newEntryList(length) (Entry)malloc(length * sizeof(struct entry))
|
k ^= k >> 24;
|
||||||
|
k *= m;
|
||||||
|
|
||||||
// 哈希结构
|
h *= m;
|
||||||
typedef struct hashMap *HashMap;
|
h ^= k;
|
||||||
|
|
||||||
#define newHashMap() NEW(struct hashMap)
|
data += 4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
switch (len) {
|
||||||
|
case 3:
|
||||||
|
h ^= data[2] << 16;
|
||||||
|
case 2:
|
||||||
|
h ^= data[1] << 8;
|
||||||
|
case 1:
|
||||||
|
h ^= data[0];
|
||||||
|
h *= m;
|
||||||
|
}
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= m;
|
||||||
|
h ^= h >> 15;
|
||||||
|
return h % map->len;
|
||||||
|
}
|
||||||
|
Iterator GetIterator(HashMapType map) {
|
||||||
|
Iterator iter = (Iterator)malloc(sizeof(struct Iter));
|
||||||
|
iter->HashNext = HasNext;
|
||||||
|
iter->Next = Next;
|
||||||
|
iter->count = 0;
|
||||||
|
iter->cur = map->entry_list[0];
|
||||||
|
iter->map = map;
|
||||||
|
for (int i = 0; i < map->len; i++) {
|
||||||
|
|
||||||
// 哈希函数类型
|
if (map->entry_list[i]->next != NULL) {
|
||||||
typedef int(*HashCode)(HashMap, let key);
|
iter->index = i;
|
||||||
|
iter->cur = map->entry_list[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
HashNodeType Next(Iterator iter) {
|
||||||
|
HashMapType map = iter->map;
|
||||||
|
if (iter->count >= map->size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (iter->cur->next != NULL) {
|
||||||
|
iter->cur = iter->cur->next;
|
||||||
|
iter->count++;
|
||||||
|
return iter->cur;
|
||||||
|
}
|
||||||
|
unsigned int i = iter->index;
|
||||||
|
while (map->entry_list[i + 1]->next == NULL) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
iter->index = i + 1;
|
||||||
|
iter->cur = map->entry_list[i + 1]->next;
|
||||||
|
iter->count++;
|
||||||
|
return iter->cur;
|
||||||
|
}
|
||||||
|
const void* Get(const void* key, HashMapType map) {
|
||||||
|
if (key == NULL)
|
||||||
|
return NULL;
|
||||||
|
const char* tmp = (const char*)key;
|
||||||
|
unsigned int hash = map->Hash(key, strlen(tmp), map);
|
||||||
|
HashNodeType cur = map->entry_list[hash];
|
||||||
|
while (cur->next != NULL) {
|
||||||
|
cur = cur->next;
|
||||||
|
if (map->KeyEqual(cur->key, key)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* code */
|
||||||
|
}
|
||||||
|
|
||||||
// 判等函数类型
|
return cur->value;
|
||||||
typedef Boolean(*Equal)(let key1, let key2);
|
}
|
||||||
|
void Push(const void* key, const void* value, HashMapType map) {
|
||||||
|
if (key == NULL)
|
||||||
|
return;
|
||||||
|
// 检查负载因子 负载因子过大 容易出现冲突,需要扩容来解决
|
||||||
|
if (map->factor > 0.7) {
|
||||||
|
int oldLen = map->len;
|
||||||
|
map->len = oldLen * 2;
|
||||||
|
HashNodeType* oldList = map->entry_list;
|
||||||
|
map->entry_list = (HashNodeType*)malloc(map->len * sizeof(HashNodeType));
|
||||||
|
if (map->entry_list == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 初始化头指针数组
|
||||||
|
IniteHashNodeTypeList(map->entry_list, map->len);
|
||||||
|
// 重新计算所有元素hash值 重新放置
|
||||||
|
int i = 0;
|
||||||
|
while (i < oldLen) {
|
||||||
|
/* code */
|
||||||
|
HashNodeType cur = NULL;
|
||||||
|
while (oldList[i]->next != NULL) {
|
||||||
|
cur = oldList[i]->next;
|
||||||
|
cur->pre->next = cur->next;
|
||||||
|
cur->next->pre = cur->pre;
|
||||||
|
unsigned int hash = map->Hash(cur->key, strlen((const char*)cur->key), map);
|
||||||
|
HashNodeType tail = map->entry_list[hash];
|
||||||
|
while (tail->next != NULL) {
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
tail->next = cur;
|
||||||
|
cur->next = NULL;
|
||||||
|
cur->pre = tail;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
map->factor = map->size * 1.0 / map->len;
|
||||||
|
free(oldList);
|
||||||
|
}
|
||||||
|
unsigned int hash = map->Hash(key, strlen((const char*)key), map);
|
||||||
|
HashNodeType insert = (HashNodeType)malloc(sizeof(struct HashNode));
|
||||||
|
if (insert == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insert->key = key;
|
||||||
|
insert->value = value;
|
||||||
|
HashNodeType cur = map->entry_list[hash];
|
||||||
|
while (cur->next != NULL) {// 尾插法
|
||||||
|
cur = cur->next;
|
||||||
|
if (map->KeyEqual(cur->key, key)) { // 出现一致的key 进行替换
|
||||||
|
cur->pre->next = insert;
|
||||||
|
insert->pre = cur->pre;
|
||||||
|
insert->next = cur->next;
|
||||||
|
if (cur->next != NULL)
|
||||||
|
cur->next->pre = insert;
|
||||||
|
map->factor = map->size * 1.0 / map->len;
|
||||||
|
map->size++;
|
||||||
|
free(cur);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cur->next == NULL) {
|
||||||
|
cur->next = insert;
|
||||||
|
insert->pre = cur;
|
||||||
|
insert->next = NULL;
|
||||||
|
map->factor = map->size * 1.0 / map->len;
|
||||||
|
map->size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Destroy(struct Iter* iter) {
|
||||||
|
if (iter->cur)
|
||||||
|
free(iter->cur);
|
||||||
|
free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
// 添加键函数类型
|
// 清空所有元素,数组恢复初始大小
|
||||||
typedef void(*Put)(HashMap hashMap, let key, let value);
|
void Clear(HashMapType map) {
|
||||||
|
int oldLen = map->len;
|
||||||
|
map->len = BASE;
|
||||||
|
HashNodeType* oldList = map->entry_list;
|
||||||
|
map->entry_list = (HashNodeType*)malloc(map->len * sizeof(HashNodeType));
|
||||||
|
// 初始化头指针数组
|
||||||
|
if (map->entry_list != NULL) {
|
||||||
|
IniteHashNodeTypeList(map->entry_list, BASE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
map->factor = 0;
|
||||||
|
map->size = 0;
|
||||||
|
// 删除所有元素
|
||||||
|
int i = 0;
|
||||||
|
while (i < oldLen) {
|
||||||
|
/* code */
|
||||||
|
HashNodeType cur = NULL;
|
||||||
|
while (oldList[i]->next != NULL) {
|
||||||
|
cur = oldList[i]->next;
|
||||||
|
cur->pre->next = cur->next;
|
||||||
|
cur->next->pre = cur->pre;
|
||||||
|
free(cur);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
free(oldList);
|
||||||
|
}
|
||||||
|
void Del(const void* key, HashMapType map) {
|
||||||
|
if (key == NULL)
|
||||||
|
return;
|
||||||
|
unsigned int hash = map->Hash(key, strlen((const char*)key), map);
|
||||||
|
HashNodeType cur = map->entry_list[hash];
|
||||||
|
while (cur->next != NULL) {
|
||||||
|
cur = cur->next;
|
||||||
|
if (map->KeyEqual(cur->key, key)) {
|
||||||
|
cur->pre->next = cur->next;
|
||||||
|
if (cur->next != NULL)
|
||||||
|
cur->next->pre = cur->pre;
|
||||||
|
map->size--;
|
||||||
|
free(cur);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map->factor = map->size * 1.0 / map->len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取键对应值的函数类型
|
HashMapType CreateHashMap() {
|
||||||
typedef let(*Get)(HashMap hashMap, let key);
|
HashMapType map = (HashMapType)malloc(sizeof(struct HashMap));
|
||||||
|
map->Clear = Clear;
|
||||||
// 删除键的函数类型
|
map->Get = Get;
|
||||||
typedef let(*Remove)(HashMap hashMap, let key);
|
map->Del = Del;
|
||||||
|
map->Push = Push;
|
||||||
// 清空Map的函数类型
|
map->Hash = Hash;
|
||||||
typedef void(*Clear)(HashMap hashMap);
|
map->KeyEqual = KeyEqual;
|
||||||
|
map->IsEmpty = IsEmpty;
|
||||||
// 判断键值是否存在的函数类型
|
map->size = 0;
|
||||||
typedef Boolean(*Exists)(HashMap hashMap, let key);
|
map->len = BASE;
|
||||||
|
map->factor = 0;
|
||||||
typedef struct hashMap {
|
map->entry_list = (HashNodeType*)malloc(sizeof(HashNodeType) * BASE);
|
||||||
int size; // 当前大小
|
IniteHashNodeTypeList(map->entry_list, BASE);
|
||||||
int listSize; // 有效空间大小
|
return map;
|
||||||
HashCode hashCode; // 哈希函数
|
}
|
||||||
Equal equal; // 判等函数
|
|
||||||
Entry list; // 存储区域
|
|
||||||
Put put; // 添加键的函数
|
|
||||||
Get get; // 获取键对应值的函数
|
|
||||||
Remove remove; // 删除键
|
|
||||||
Clear clear; // 清空Map
|
|
||||||
Exists exists; // 判断键是否存在
|
|
||||||
Boolean autoAssign; // 设定是否根据当前数据量动态调整内存大小,默认开启
|
|
||||||
}*HashMap;
|
|
||||||
|
|
||||||
// 迭代器结构
|
|
||||||
typedef struct hashMapIterator {
|
|
||||||
Entry entry; // 迭代器当前指向
|
|
||||||
int count; // 迭代次数
|
|
||||||
int hashCode; // 键值对的哈希值
|
|
||||||
HashMap hashMap;
|
|
||||||
}*HashMapIterator;
|
|
||||||
|
|
||||||
#define newHashMapIterator() NEW(struct hashMapIterator)
|
|
||||||
|
|
||||||
// 默认哈希函数
|
|
||||||
static int defaultHashCode(HashMap hashMap, let key);
|
|
||||||
|
|
||||||
// 默认判断键值是否相等
|
|
||||||
static Boolean defaultEqual(let key1, let key2);
|
|
||||||
|
|
||||||
// 默认添加键值对
|
|
||||||
static void defaultPut(HashMap hashMap, let key, let value);
|
|
||||||
|
|
||||||
// 默认获取键对应值
|
|
||||||
static let defaultGet(HashMap hashMap, let key);
|
|
||||||
|
|
||||||
// 默认删除键
|
|
||||||
static let defaultRemove(HashMap hashMap, let key);
|
|
||||||
|
|
||||||
// 默认判断键是否存在
|
|
||||||
static Boolean defaultExists(HashMap hashMap, let key);
|
|
||||||
|
|
||||||
// 默认清空Map
|
|
||||||
static void defaultClear(HashMap hashMap);
|
|
||||||
|
|
||||||
// 重新构建
|
|
||||||
static void resetHashMap(HashMap hashMap, int listSize);
|
|
||||||
|
|
||||||
// 创建一个哈希结构
|
|
||||||
HashMap createHashMap(HashCode hashCode, Equal equal);
|
|
||||||
|
|
||||||
// 创建哈希结构迭代器
|
|
||||||
HashMapIterator createHashMapIterator(HashMap hashMap);
|
|
||||||
|
|
||||||
// 迭代器是否有下一个
|
|
||||||
Boolean hasNextHashMapIterator(HashMapIterator iterator);
|
|
||||||
|
|
||||||
// 迭代到下一次
|
|
||||||
HashMapIterator nextHashMapIterator(HashMapIterator iterator);
|
|
||||||
|
|
||||||
// 释放迭代器内存
|
|
||||||
void freeHashMapIterator(HashMapIterator * iterator);
|
|
||||||
|
|
||||||
#endif // !__HASHMAP_H__
|
|
|
@ -19,7 +19,7 @@ extern int FrameworkInit();
|
||||||
extern void ApplicationOtaTaskInit(void);
|
extern void ApplicationOtaTaskInit(void);
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
printf("Hello, world! \n");
|
printf("Hello, world! !\n");
|
||||||
FrameworkInit();
|
FrameworkInit();
|
||||||
#ifdef APPLICATION_OTA
|
#ifdef APPLICATION_OTA
|
||||||
ApplicationOtaTaskInit();
|
ApplicationOtaTaskInit();
|
||||||
|
|
Loading…
Reference in New Issue