diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index 45df5f5d5..f1e41d483 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -240,5 +240,8 @@ menu "test app" bool "Config test soft timer" default n + config USER_TEST_HASH_MAP + bool "Config test hash map" + default n endif endmenu diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 1cf919846..a53c1a610 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -25,6 +25,10 @@ endif ifeq ($(CONFIG_ADD_XIZI_FETURES),y) SRC_FILES := test_shell.c + ifeq ($(CONFIG_USER_TEST_HASH_MAP),y) + SRC_FILES += ./test_hash/test_hash.c + endif + ifeq ($(CONFIG_USER_TEST_ADC),y) SRC_FILES += test_adc.c endif diff --git a/APP_Framework/Applications/app_test/test_hash/README.md b/APP_Framework/Applications/app_test/test_hash/README.md new file mode 100644 index 000000000..ca124bd1a --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/README.md @@ -0,0 +1,241 @@ +# 一、概要 +## (一)哈希表主要设计有三个数据结构: +1. HashNode:存放数据的节点;哈希表不负责key、value的内存管理(避免内存管理错误); hash_code用于快速查找; +```c +typedef struct Node +{ + int hash_code; + void* key; + void* value; + struct Node* next_node; +} HashNode; +``` +2. HashMap:存放哈希表的总体数据信息以及相关函数;table为哈希位桶,默认为16个;hashCode将键转换为尽量唯一的哈希值(中文、英文、数值的哈希函数各不相同,在使用时需要额外注意); +```c +typedef struct Map +{ + int table_size; + int capacity; + HashNode** table; + int (*hashCode)(const void* key); + bool (*keyEqual)(const void* left_key, const void* right_key); +} HashMap; +``` +3. HashMapIterator:哈希表迭代器;迭代器迭代后需要重置;迭代过程中哈希表变动后结果未定义;hasNext 是否存在下一个非空节点; next 获取下一个非空节点; +```c +typedef struct Iterator +{ + HashMap* hash_map; + int current_table_index; + HashNode* current_node_pointer; + bool (*hasNext) (struct Iterator*); + HashNode* (*next)(struct Iterator*); + void (*reset)(struct Iterator*); +} HashMapIterator; +``` + +## (二)支持的操作如下表所示: +| 函数声明 | 函数描述| +|-------------|------------| +| HashMap* hashMapCreate(int (*hashCode)(const void*), bool (*keyEqual)(const void*, const void*))|创建一个空的哈希表,默认位桶个数为16| +|void hashMapDelete(HashMap* hash_map)|删除哈希表并释放相关存储空间| +|void hashMapClear(HashMap* hash_map)|清空哈希表的数据,但是已扩展的位桶不缩小| +|HashMapIterator* hashMapIteratorCreate(HashMap* hash_map)|创建一个哈希表迭代器,方便非空元素遍历| +|bool hashMapSet(HashMap* hash_map, void* key, void* value)|添加数据,若已存在则覆盖| +|void* hashMapGet(HashMap* hash_map, const void* key)|获取数据,返回value地址| +|bool hashMapRemove(HashMap* hash_map,void* key)|移除数据| + +# 二、注意事项 +- 在使用hashmap时,键、值最好不要使用临时变量,临时变量在超出周期后会被自动回收,会造成未预期异常,hashmap不负责键、值的内存管理 +- 在选择指定的哈希函数后,不要使用这个哈希函数不支持的键类型,比如一个只支持英文的哈希函数在使用汉语作为键时会出现未定义异常 + +# 三、测试流程 +## (一)流程 +1. 创建一个空的hashmap +2. 向其中添加一定的元素 +3. 使用迭代器遍历非空节点 +4. 遍历所有的位桶 +5. 再次添加一定的元素 +6. 遍历所有的位桶 +7. 测试查找功能 +8. 测试删除功能 +9. 遍历所有的位桶 +10. 测试修改功能 +11. 遍历所有的位桶 +12. 添加更多的数据以触发扩容 +13. 遍历所有的位桶 +14. 测试查找功能 +15. 遍历所有的位桶 +16. 清空哈希表 +17. 遍历所有的位桶 +18. 销毁哈希表 +## (二)代码 +```c +typedef struct Stu +{ + char *student_number; + char *name; + int age; + char gender; +} Student; + +Student* getStudent(char *student_number, char *name,int age,char gender) +{ + Student* new_student = (Student*)malloc(sizeof(Student)); + if (new_student != NULL) + { + new_student->student_number = (char*)malloc(strlen(student_number) + 1); + strcpy(new_student->student_number,student_number); + new_student->name = (char*)malloc(strlen(name) + 1); + strcpy(new_student->name,name); + new_student->age = age; + new_student->gender = gender; + return new_student; + } + return NULL; +} + +void printfHash(HashMap *hash_map) +{ + int table_size = hash_map->table_size; + int capacity = hash_map->capacity; + printf("-------------------------------------总体情况: table_size: %d, capacity: %d------------------------------------------------\n", table_size, capacity); + for (int i = 0; i < table_size; i++) + { + printf("----------------------------------------------------index: %d --------------------------------------------------------------\n", i); + HashNode *head_node = hash_map->table[i]; + if (head_node == NULL) + { + printf("NULL\n"); + } + else + { + while (head_node != NULL) + { + Student *student = (Student *)head_node->value; + printf("hash_code: %d, key: %s value: {student_number: %s name: %s age:%d gender: %c } \n", head_node->hash_code, (char *)head_node->key, student->student_number, student->name, student->age, student->gender); + head_node = head_node->next_node; + } + } + } +} + +void TestHash(void) +{ + printf("创建一个(字符串---结构体:Student)类型的哈希表,自定义或选择对应的哈希函数和比较器\n"); + //1.创建一个空的hashmap + HashMap *hash_map = hashMapCreate(hashCodeCharStringELF, charStringEqual); + Student* value_temp = NULL; + if (hash_map != NULL) + { + printf("创建哈希表成功,现在向里面添加一些数据\n"); + //2.向其中添加一定的元素 + hashMapSet(hash_map,"20230001",getStudent("20230001","张一",21,'M')); + hashMapSet(hash_map,"20230002",getStudent("20230002","张二",22,'M')); + hashMapSet(hash_map,"20230003",getStudent("20230003","张三",23,'M')); + + printf("现在遍历这个哈系表,创建一个迭代器进行迭代,先输出哈系表的总体情况: table_size: %d, capacity: %d\n", hash_map->table_size, hash_map->capacity); + //3.使用迭代器遍历非空节点 + HashMapIterator *iterator = hashMapIteratorCreate(hash_map); + if (iterator != NULL) + { + printf("迭代器创建成功,开始迭代\n"); + while (iterator->hasNext(iterator)) + { + HashNode *node = iterator->next(iterator); + Student *student = (Student *)node->value; + printf("hash_code: %d, key: %s value: {student_number: %s name: %s age:%d gender: %c } \n", node->hash_code, (char *)node->key, student->student_number, student->name, student->age, student->gender); + } + } + printf("现在换一种方法直接遍历,查看数据的位置信息\n"); + //4.遍历所有的位桶 + printfHash(hash_map); + printf("再添加几条信息\n"); + //5.再次添加一定的元素 + hashMapSet(hash_map,"20230011",getStudent("20230011","赵一",21,'M')); + hashMapSet(hash_map,"20230012",getStudent("20230012","赵二",22,'M')); + hashMapSet(hash_map,"20230013",getStudent("20230013","赵三",23,'M')); + //6.遍历所有的位桶 + printfHash(hash_map); + printf("查找学号为20230012的学生信息:\n"); + //7.测试查找功能 + Student *value = hashMapGet(hash_map, "20230012"); + printf(" value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + printf("删除学号为20230011的学生信息:\n"); + //8.测试删除功能 + if (hashMapRemove(hash_map, "20230011")) + { + printf("删除成功!\n"); + } + else + { + printf("删除失败?\n"); + } + //9.遍历所有的位桶 + printfHash(hash_map); + printf("修改赵三的年龄为18,查出对应数据结构后拿到指针进行修改:\n"); + //10.测试修改功能 + value = hashMapGet(hash_map, "20230013"); + printf("value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + value->age = 18; + printf("value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + //11.遍历所有的位桶 + printfHash(hash_map); + printf("添加更多的数据以触发哈希表扩容\n"); + //12.添加更多的数据以触发扩容 + hashMapSet(hash_map,"20230111",getStudent("20230111","王一",21,'M')); + hashMapSet(hash_map,"20230112",getStudent("20230112","王二",22,'M')); + hashMapSet(hash_map,"20230113",getStudent("20230113","王三",23,'M')); + hashMapSet(hash_map,"20230114",getStudent("20230114","王四",24,'M')); + hashMapSet(hash_map,"20230115",getStudent("20230115","王五",25,'M')); + hashMapSet(hash_map,"20230116",getStudent("20230116","王六",26,'M')); + hashMapSet(hash_map,"20230117",getStudent("20230117","王七",27,'M')); + hashMapSet(hash_map,"20230118",getStudent("20230118","王八",28,'M')); + hashMapSet(hash_map,"20230119",getStudent("20230119","王九",29,'M')); + hashMapSet(hash_map,"20231111",getStudent("20231111","刘一",21,'M')); + hashMapSet(hash_map,"20231112",getStudent("20231112","刘二",22,'M')); + hashMapSet(hash_map,"20231113",getStudent("20231113","刘三",23,'M')); + hashMapSet(hash_map,"20231114",getStudent("20231114","刘四",24,'M')); + hashMapSet(hash_map,"20231115",getStudent("20231115","刘五",25,'M')); + hashMapSet(hash_map,"20231116",getStudent("20231116","刘六",26,'M')); + hashMapSet(hash_map,"20231117",getStudent("20231117","刘七",27,'M')); + hashMapSet(hash_map,"20231118",getStudent("20231118","刘八",28,'M')); + hashMapSet(hash_map,"20231119",getStudent("20231119","刘九",29,'M')); + //13.遍历所有的位桶 + printfHash(hash_map); + printf("查找学号为20231119的学生信息:\n"); + //14.测试查找功能 + value = hashMapGet(hash_map, "20231119"); + printf(" value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + //15.遍历所有的位桶 + printfHash(hash_map); + //16.清空哈希表 + printf("清空哈希标\n"); + hashMapClear(hash_map); + //17.遍历所有的位桶 + printfHash(hash_map); + //18.销毁哈希表 + hashMapDelete(hash_map); + } +} + +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +``` +# 四、测试结果 +1. 创建一个新的哈希表,添加三个元素并输出结果
+![创建一个新的哈希表,添加三个元素并输出结果](images/1.png) +2. 再次添加三个元素并输出结果
+![再次添加三个元素并输出结果](images/2.png) +3. 查找数据结果输出,删除指定数据后输出结果
+![查找数据结果输出,删除指定数据后输出结果](images/3.png) +4. 修改指定数据后输出结果
+![修改指定数据后输出结果](images/4.png) +5. 添加更多数据触发扩容操作后输出结果
+![添加更多数据触发扩容操作后输出结果](images/5-1.png) +![添加更多数据触发扩容操作后输出结果](images/5-2.png) +6. 扩容后进行查询操作,然后输出结果
+![扩容后进行查询操作,然后输出结果](images/6-1.png) +![扩容后进行查询操作,然后输出结果](images/6-2.png) +7. 清空哈希表后输出结果
+![清空哈希表后输出结果](images/7-1.png) +![清空哈希表后输出结果](images/7-2.png) diff --git a/APP_Framework/Applications/app_test/test_hash/images/1.png b/APP_Framework/Applications/app_test/test_hash/images/1.png new file mode 100755 index 000000000..ab472ace4 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/1.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/2.png b/APP_Framework/Applications/app_test/test_hash/images/2.png new file mode 100755 index 000000000..1ba5abfdb Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/2.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/3.png b/APP_Framework/Applications/app_test/test_hash/images/3.png new file mode 100755 index 000000000..77feb125a Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/3.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/4.png b/APP_Framework/Applications/app_test/test_hash/images/4.png new file mode 100755 index 000000000..de7ea897d Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/4.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/5-1.png b/APP_Framework/Applications/app_test/test_hash/images/5-1.png new file mode 100755 index 000000000..70568e3c6 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/5-1.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/5-2.png b/APP_Framework/Applications/app_test/test_hash/images/5-2.png new file mode 100755 index 000000000..e9894b648 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/5-2.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/6-1.png b/APP_Framework/Applications/app_test/test_hash/images/6-1.png new file mode 100755 index 000000000..695e38d8a Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/6-1.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/6-2.png b/APP_Framework/Applications/app_test/test_hash/images/6-2.png new file mode 100755 index 000000000..200acff70 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/6-2.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/7-1.png b/APP_Framework/Applications/app_test/test_hash/images/7-1.png new file mode 100755 index 000000000..34d06247b Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/7-1.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/images/7-2.png b/APP_Framework/Applications/app_test/test_hash/images/7-2.png new file mode 100755 index 000000000..e07ea310c Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/images/7-2.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/test_hash.c b/APP_Framework/Applications/app_test/test_hash/test_hash.c new file mode 100644 index 000000000..8a16d9e82 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.c @@ -0,0 +1,640 @@ +#include +#include +#include +#include +#include"transform.h" + +typedef struct Node +{ + int hash_code; + void* key; + void* value; + struct Node* next_node; +} HashNode; + +typedef struct Map +{ + int table_size; + int capacity; + HashNode** table; + int (*hashCode)(const void* key); + bool (*keyEqual)(const void* left_key, const void* right_key); +} HashMap; + +typedef struct Iterator +{ + HashMap* hash_map; + int current_table_index; + HashNode* current_node_pointer; + bool (*hasNext) (struct Iterator*); + HashNode* (*next)(struct Iterator*); + void (*reset)(struct Iterator*); +} HashMapIterator; + +HashMap* hashMapCreate(int (*hashCode)(const void*), bool (*keyEqual)(const void*, const void*)); + +void hashMapDelete(HashMap* hash_map); + +void hashMapClear(HashMap* hash_map); + +HashMapIterator* hashMapIteratorCreate(HashMap* hash_map); + +bool hashMapSet(HashMap* hash_map, void* key, void* value); + +void* hashMapGet(HashMap* hash_map, const void* key); + +bool hashMapRemove(HashMap* hash_map,void* key); + +int hashCodeIntSimple(const void* int_key); + +int hashCodeCharStringELF(const void* string_key); + +bool intEqual(const void* left_value, const void* right_value); + +bool charStringEqual(const void* left_value, const void* right_value); + +int _indexFor(int hash_code, int table_size) +{ + return hash_code & (table_size - 1); +} + +HashNode* _createNewHashNode(int hash_code,void* key, void* value) +{ + HashNode* newHashNode = (HashNode*) malloc (sizeof(HashNode)); + if (newHashNode != NULL) + { + newHashNode->hash_code = hash_code; + newHashNode->key = key; + newHashNode->value = value; + newHashNode->next_node = NULL; + return newHashNode; + } + return NULL; +} + +HashNode** _getNewNodeTableBySize(int table_size) +{ + HashNode** new_table = (HashNode**) malloc (table_size * sizeof(HashNode*)); + if (new_table != NULL) + { + for (int i = 0; i < table_size; i++) + { + new_table[i] = NULL; + } + return new_table; + } + return NULL; +} + +HashNode* _loadNextNoneNullNode(HashMapIterator* iterator) +{ + if (iterator != NULL) + { + HashMap* hash_map = iterator->hash_map; + int current_table_index = iterator->current_table_index; + HashNode* current_node_pointer = iterator->current_node_pointer; + HashNode* temp_node_pointer = NULL; + //Not initialized, Locate the first non-empty head node + if (current_table_index == -1) + { + for (int i = 0; i < hash_map->table_size; i++) + { + iterator->current_table_index = i; + temp_node_pointer = hash_map->table[i]; + if (temp_node_pointer != NULL) + { + iterator->current_node_pointer = temp_node_pointer; + return temp_node_pointer; + } + } + return NULL; + } + else + { + //Initialized, but there is no non-empty node + if (current_node_pointer == NULL) + { + return NULL; + } + else + { + if (current_node_pointer->next_node != NULL) + { + iterator->current_node_pointer = current_node_pointer->next_node; + return current_node_pointer->next_node; + } + else + { + iterator->current_node_pointer = NULL; + for (int begin = current_table_index + 1; begin < hash_map->table_size; begin++) + { + iterator->current_table_index = begin; + temp_node_pointer = hash_map->table[begin]; + if (temp_node_pointer != NULL) + { + iterator->current_node_pointer = temp_node_pointer; + return temp_node_pointer; + } + } + return NULL; + } + } + } + } + return NULL; +} + +bool _hashNext (HashMapIterator* iterator) + { + if (iterator == NULL) + { + return false; + } + if (iterator->current_table_index == -1) + { + _loadNextNoneNullNode(iterator); + } + return iterator->current_node_pointer == NULL ? false : true; +} + +HashNode* _next(HashMapIterator* iterator) +{ + if (iterator == NULL) + { + return NULL; + } + if (iterator->current_table_index == -1) + { + _loadNextNoneNullNode(iterator); + } + HashNode* next_node = iterator->current_node_pointer; + if (next_node == NULL) + { + return NULL; + } + else + { + _loadNextNoneNullNode(iterator); + return next_node; + } +} + +void _reset(HashMapIterator* iterator) +{ + if (iterator != NULL) + { + iterator->current_table_index = -1; + iterator->current_node_pointer = NULL; + } +} + +void _releaseNode(HashNode* node) +{ + if (node != NULL) + { + free(node); + } +} + +void _releaseNodeList(HashNode* head_node) +{ + HashNode* tmp = NULL; + while (head_node != NULL) + { + tmp = head_node; + head_node = head_node->next_node; + _releaseNode(tmp); + } +} + +void _transferNode(HashNode* new_head_node, HashNode* old_node) +{ + if (new_head_node != NULL && old_node != NULL) + { + while (new_head_node->next_node != NULL) + { + new_head_node = new_head_node->next_node; + } + new_head_node->next_node = old_node; + } +} + +void _resize(HashMap* hash_map) +{ + if (hash_map != NULL) + { + int old_table_size = hash_map->table_size; + if (old_table_size == 65536) + { + return; + } + int new_table_size = old_table_size <<1; + HashNode** new_hash_table = _getNewNodeTableBySize(new_table_size); + if (new_hash_table != NULL) + { + HashNode** old_hash_table = hash_map->table; + for (int i = 0; i < old_table_size; i++) + { + HashNode* old_head_node = old_hash_table[i]; + HashNode* temp_node; + while (old_head_node != NULL) + { + temp_node = old_head_node; + old_head_node = old_head_node->next_node; + temp_node->next_node = NULL; + int new_index = _indexFor(temp_node->hash_code,new_table_size); + if (new_hash_table[new_index] == NULL) + { + new_hash_table[new_index] = temp_node; + } + else + { + _transferNode(new_hash_table[new_index],temp_node); + } + } + old_hash_table[i] = NULL; + } + hash_map->table_size = new_table_size; + hash_map->table = new_hash_table; + free(old_hash_table); + } + } +} + +HashMap* hashMapCreate(int (*hashCode)(const void*), bool (*keyEqual)(const void*, const void*)) +{ + HashMap* new_hash_map = (HashMap*) malloc(sizeof(HashMap)); + if (new_hash_map == NULL) + { + return NULL; + } + new_hash_map->table_size = 1<<4; + new_hash_map->capacity = 0; + HashNode** table = _getNewNodeTableBySize(new_hash_map->table_size); + if (table == NULL) + { + free(new_hash_map); + return NULL; + } + new_hash_map->table =table; + new_hash_map->hashCode = hashCode; + new_hash_map->keyEqual = keyEqual; + return new_hash_map; +} + +HashMapIterator* hashMapIteratorCreate(HashMap* hash_map) +{ + if (hash_map == NULL) + { + return NULL; + } + HashMapIterator* new_iterator = (HashMapIterator*) malloc (sizeof(HashMapIterator)); + if (new_iterator == NULL) + { + return NULL; + } + new_iterator->hash_map = hash_map; + new_iterator->current_table_index = -1; + new_iterator->current_node_pointer = NULL; + new_iterator->hasNext = _hashNext; + new_iterator->next = _next; + new_iterator->reset = _reset; + return new_iterator; +} + +void hashMapClear(HashMap* hash_map) +{ + if (hash_map != NULL) + { + for (int i = 0; i < hash_map->table_size; i++) + { + _releaseNodeList(hash_map->table[i]); + hash_map->table[i] = NULL; + } + hash_map->capacity = 0; + } +} + +void hashMapDelete(HashMap* hash_map) +{ + if (hash_map != NULL) + { + hashMapClear(hash_map); + free(hash_map->table); + free(hash_map); + } +} + +bool hashMapSet(HashMap* hash_map, void* key, void* value) +{ + if (hash_map == NULL) + { + return false; + } + int hash_code = hash_map->hashCode(key); + HashNode* new_node = _createNewHashNode(hash_code,key,value); + if (new_node == NULL) + { + return false; + } + int index = _indexFor(hash_code,hash_map->table_size); + HashNode* head_node = hash_map->table[index]; + if (head_node == NULL) + { + hash_map->table[index] = new_node; + hash_map->capacity ++; + } + else + { + while (head_node != NULL) + { + if (head_node->hash_code == hash_code && hash_map->keyEqual(head_node->key,key)) + { + head_node->value = value; + break; + } + else + { + if (head_node->next_node == NULL) + { + head_node->next_node = new_node; + hash_map->capacity ++; + break; + } + else + { + head_node = head_node->next_node; + } + } + } + } + if (hash_map->capacity >= hash_map->table_size) + { + _resize(hash_map); + } + return true; +} + +void* hashMapGet(HashMap* hash_map,const void* key) +{ + if (hash_map == NULL) + { + return false; + } + int hash_code = hash_map->hashCode(key); + int index = _indexFor(hash_code,hash_map->table_size); + HashNode* head_node = hash_map->table[index]; + if (head_node == NULL) + { + return NULL; + } + else + { + do + { + if (head_node->hash_code == hash_code && hash_map->keyEqual(head_node->key,key)) + { + return head_node->value; + } + head_node = head_node->next_node; + } while (head_node != NULL); + return NULL; + } +} + +bool hashMapRemove(HashMap* hash_map, void* key) +{ + if (hash_map == NULL) + { + return false; + } + int hash_code = hash_map->hashCode(key); + int index = _indexFor(hash_code,hash_map->table_size); + HashNode* head_node = hash_map->table[index]; + if (head_node == NULL) + { + return false; + } + else + { + if (head_node->hash_code == hash_code && hash_map->keyEqual(head_node->key,key)) + { + hash_map->table[index] = head_node->next_node; + _releaseNode(head_node); + hash_map->capacity --; + } + else + { + HashNode* pre_node = head_node; + head_node = head_node->next_node; + while (head_node != NULL) + { + if (head_node->hash_code == hash_code && hash_map->keyEqual(head_node->key,key)) + { + pre_node->next_node = head_node->next_node; + _releaseNode(head_node); + hash_map->capacity --; + return true; + } + pre_node = head_node; + head_node = head_node->next_node; + } + return false; + } + } +} + +int hashCodeIntSimple(const void* int_key) +{ + const int* temp = (int*)(int_key); + return *temp < 0 ? 0 : *temp; +} + +int hashCodeCharStringELF(const void* string_key) +{ + const char* str = (char*)(string_key); + unsigned int hash_code=0; + unsigned int x=0; + while(*str) + { + hash_code=(hash_code<<4)+*str; + if((x=hash_code & 0xf0000000)!=0) + { + hash_code^=(x>>24); + hash_code&=~x; + } + str++; + } + hash_code = hash_code & 0x7fffffff; + return hash_code > __INT_MAX__ ? __INT_MAX__ : hash_code; +} + +bool intEqual(const void* left_value, const void* right_value) +{ + if (left_value == NULL || right_value == NULL) + { + return false; + } + return *( (int*)left_value) == *( (int*)right_value); +} + +bool charStringEqual(const void* left_value, const void* right_value) +{ + if (left_value == NULL || right_value == NULL) + { + return false; + } + return strcmp((char*)left_value,(char*)right_value) == 0; +} + +/*******************************test*************************************/ +typedef struct Stu +{ + char *student_number; + char *name; + int age; + char gender; +} Student; + +Student* getStudent(char *student_number, char *name,int age,char gender) +{ + Student* new_student = (Student*)malloc(sizeof(Student)); + if (new_student != NULL) + { + new_student->student_number = (char*)malloc(strlen(student_number) + 1); + strcpy(new_student->student_number,student_number); + new_student->name = (char*)malloc(strlen(name) + 1); + strcpy(new_student->name,name); + new_student->age = age; + new_student->gender = gender; + return new_student; + } + return NULL; +} + +void printfHash(HashMap *hash_map) +{ + int table_size = hash_map->table_size; + int capacity = hash_map->capacity; + printf("-------------------------------------总体情况: table_size: %d, capacity: %d------------------------------------------------\n", table_size, capacity); + for (int i = 0; i < table_size; i++) + { + printf("----------------------------------------------------index: %d --------------------------------------------------------------\n", i); + HashNode *head_node = hash_map->table[i]; + if (head_node == NULL) + { + printf("NULL\n"); + } + else + { + while (head_node != NULL) + { + Student *student = (Student *)head_node->value; + printf("hash_code: %d, key: %s value: {student_number: %s name: %s age:%d gender: %c } \n", head_node->hash_code, (char *)head_node->key, student->student_number, student->name, student->age, student->gender); + head_node = head_node->next_node; + } + } + } +} + +void TestHash(void) +{ + printf("创建一个(字符串---结构体:Student)类型的哈希表,自定义或选择对应的哈希函数和比较器\n"); + //1.创建一个空的hashmap + HashMap *hash_map = hashMapCreate(hashCodeCharStringELF, charStringEqual); + Student* value_temp = NULL; + if (hash_map != NULL) + { + printf("创建哈希表成功,现在向里面添加一些数据\n"); + //2.向其中添加一定的元素 + hashMapSet(hash_map,"20230001",getStudent("20230001","张一",21,'M')); + hashMapSet(hash_map,"20230002",getStudent("20230002","张二",22,'M')); + hashMapSet(hash_map,"20230003",getStudent("20230003","张三",23,'M')); + + printf("现在遍历这个哈系表,创建一个迭代器进行迭代,先输出哈系表的总体情况: table_size: %d, capacity: %d\n", hash_map->table_size, hash_map->capacity); + //3.使用迭代器遍历非空节点 + HashMapIterator *iterator = hashMapIteratorCreate(hash_map); + if (iterator != NULL) + { + printf("迭代器创建成功,开始迭代\n"); + while (iterator->hasNext(iterator)) + { + HashNode *node = iterator->next(iterator); + Student *student = (Student *)node->value; + printf("hash_code: %d, key: %s value: {student_number: %s name: %s age:%d gender: %c } \n", node->hash_code, (char *)node->key, student->student_number, student->name, student->age, student->gender); + } + } + printf("现在换一种方法直接遍历,查看数据的位置信息\n"); + //4.遍历所有的位桶 + printfHash(hash_map); + printf("再添加几条信息\n"); + //5.再次添加一定的元素 + hashMapSet(hash_map,"20230011",getStudent("20230011","赵一",21,'M')); + hashMapSet(hash_map,"20230012",getStudent("20230012","赵二",22,'M')); + hashMapSet(hash_map,"20230013",getStudent("20230013","赵三",23,'M')); + //6.遍历所有的位桶 + printfHash(hash_map); + printf("查找学号为20230012的学生信息:\n"); + //7.测试查找功能 + Student *value = hashMapGet(hash_map, "20230012"); + printf(" value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + printf("删除学号为20230011的学生信息:\n"); + //8.测试删除功能 + if (hashMapRemove(hash_map, "20230011")) + { + printf("删除成功!\n"); + } + else + { + printf("删除失败?\n"); + } + //9.遍历所有的位桶 + printfHash(hash_map); + printf("修改赵三的年龄为18,查出对应数据结构后拿到指针进行修改:\n"); + //10.测试修改功能 + value = hashMapGet(hash_map, "20230013"); + printf("value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + value->age = 18; + printf("value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + //11.遍历所有的位桶 + printfHash(hash_map); + printf("添加更多的数据以触发哈希表扩容\n"); + //12.添加更多的数据以触发扩容 + hashMapSet(hash_map,"20230111",getStudent("20230111","王一",21,'M')); + hashMapSet(hash_map,"20230112",getStudent("20230112","王二",22,'M')); + hashMapSet(hash_map,"20230113",getStudent("20230113","王三",23,'M')); + hashMapSet(hash_map,"20230114",getStudent("20230114","王四",24,'M')); + hashMapSet(hash_map,"20230115",getStudent("20230115","王五",25,'M')); + hashMapSet(hash_map,"20230116",getStudent("20230116","王六",26,'M')); + hashMapSet(hash_map,"20230117",getStudent("20230117","王七",27,'M')); + hashMapSet(hash_map,"20230118",getStudent("20230118","王八",28,'M')); + hashMapSet(hash_map,"20230119",getStudent("20230119","王九",29,'M')); + hashMapSet(hash_map,"20231111",getStudent("20231111","刘一",21,'M')); + hashMapSet(hash_map,"20231112",getStudent("20231112","刘二",22,'M')); + hashMapSet(hash_map,"20231113",getStudent("20231113","刘三",23,'M')); + hashMapSet(hash_map,"20231114",getStudent("20231114","刘四",24,'M')); + hashMapSet(hash_map,"20231115",getStudent("20231115","刘五",25,'M')); + hashMapSet(hash_map,"20231116",getStudent("20231116","刘六",26,'M')); + hashMapSet(hash_map,"20231117",getStudent("20231117","刘七",27,'M')); + hashMapSet(hash_map,"20231118",getStudent("20231118","刘八",28,'M')); + hashMapSet(hash_map,"20231119",getStudent("20231119","刘九",29,'M')); + //13.遍历所有的位桶 + printfHash(hash_map); + printf("查找学号为20231119的学生信息:\n"); + //14.测试查找功能 + value = hashMapGet(hash_map, "20231119"); + printf(" value: {student_number: %s name: %s age:%d gender: %c } \n", value->student_number, value->name, value->age, value->gender); + //15.遍历所有的位桶 + printfHash(hash_map); + //16.清空哈希表 + printf("清空哈希标\n"); + hashMapClear(hash_map); + //17.遍历所有的位桶 + printfHash(hash_map); + //18.销毁哈希表 + hashMapDelete(hash_map); + } +} + +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +