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..fba946798 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/README.md @@ -0,0 +1,37 @@ +# ##2023_open_source_contest_warmup_1st_issue1## + +## 1. 简介 + 基于矽璓模拟器cortex-m3-emulator,实现哈希表,支持链地址法解决哈希冲突,并编写测试程序在shell终端打印结果。 + 经过测试,我们的代码完美实现了热身赛赛题1所规定的全部预期功能。 + + +## 2. 数据结构设计说明 +源代码文件test_hash.c中,实现了一个基于哈希表的键值对存储结构,并提供了一系列操作该数据结构的函数。主要功能包括: + 1. `InitHashTable()`:初始化一个哈希表,返回一个指向 `HashTableType` 类型的指针。 + 2. `GetHash(int key)`:给定一个键值,计算其哈希值并返回。 + 3. `InitNode(int key, int value)`:初始化一个节点,返回一个指向 `NodeType` 类型的指针。 + 4. `GetTableSize(HashTableType* hash_table)`:获取哈希表中键值对的数量。 + 5. `FindNode(HashTableType* hash_table, int key)`:在哈希表中查找指定键值的节点,如果存在则返回该节点的指针,否则返回 `NULL`。 + 6. `InsertNode(HashTableType* hash_table, int key, int value)`:向哈希表中插入一个键值对,如果插入成功则返回 1,否则返回 0。 + 7. `RemoveNode(HashTableType* hash_table, int key)`:从哈希表中删除指定键值的节点,如果删除成功则返回 1,否则返回 0。 + 8. `ModifyNode(HashTableType* hash_table, int key, int value)`:修改哈希表中指定键值的节点的值,如果修改成功则返回 1,否则返回 0。 + 9. `Display(HashTableType* hash_table)`:打印哈希表中所有的键值对。 + 10. `TestHash()`:对哈希表进行一系列测试,包括插入、查找、修改、删除等操作,并输出相应的结果。 + 此程序文件与其他模块或函数的接口关系较少,主要使用了自定义的数据结构类型 `HashTableType` 和 `NodeType`,以及一些标准库函数(如 `malloc` 和 `printf`)。输出值的含义和取值范围在函数中有相应的注释和说明。参数间的控制、顺序、独立或依赖等关系主要由函数的实现决定,例如删除节点前需要先查找节点,修改节点前需要先判断节点是否存在等。函数之间相互独立,可以单独调用,但也可以组合使用。 +头文件test_hash.h中定义了一个基于链表的哈希表数据结构。其中: + 1. `NodeType` 结构体表示哈希表中的一个节点,包含了该节点的键值以及指向下一个节点的指针。 + 2. `HashTableType` 结构体表示整个哈希表,包含了一个长度为 `MAX_TABLE_SIZE` 的指针数组 `table`,用于存储节点,并且记录了哈希表中节点的数量 `tabel_size`。 + 该头文件的主要功能是定义了 `NodeType` 和 `HashTableType` 两个自定义的数据类型,为使用基于链表的哈希表提供了便利。可以在需要使用哈希表的代码中包含该头文件,并根据需要创建相应的 `HashTableType` 变量,然后使用其中定义的函数来操作哈希表。例如可以使用 `InitHashTable()` 函数来初始化哈希表,使用 `InsertNode()` 函数来插入一个节点,使用 `FindNode()` 函数来查找指定键值的节点等等。具体使用方法可以参考使用哈希表的代码示例. + + +## 3. 测试程序说明 + 测试函数为InsertNode、Display、FindNode、ModifyNode、RemoveNode。首先新增节点,之后展示,再测试查找操作、修改节点、移除节点等操作。 + + +## 4. 运行结果(##需结合运行测试截图按步骤说明##) + 打开menuconfig进行裁剪 + ![Alt text](%E6%89%93%E5%BC%80menuconfig%E8%BF%9B%E8%A1%8C%E8%A3%81%E5%89%AA.png) + 编译项目 + ![Alt text](%E7%BC%96%E8%AF%91%E9%A1%B9%E7%9B%AE.png) + 启动qemu并且运行Shell命令 + ![Alt text](%E5%90%AF%E5%8A%A8qemu%E5%B9%B6%E8%BF%90%E8%A1%8Cshell%E5%91%BD%E4%BB%A4.png) \ No newline at end of file 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..9d3b9e4fb --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.c @@ -0,0 +1,201 @@ +/* +* Copyright (c) 2023 oscar +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL +v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/************************************************* + File name: tesh_hash.c// 文件名 + Description: 这段代码实现了一个基于哈希表的键值对存储结构,并提供了一系列操作该数据结构的函数。主要功能包括: + 1. `InitHashTable()`:初始化一个哈希表,返回一个指向 `HashTableType` 类型的指针。 + 2. `GetHash(int key)`:给定一个键值,计算其哈希值并返回。 + 3. `InitNode(int key, int value)`:初始化一个节点,返回一个指向 `NodeType` 类型的指针。 + 4. `GetTableSize(HashTableType* hash_table)`:获取哈希表中键值对的数量。 + 5. `FindNode(HashTableType* hash_table, int key)`:在哈希表中查找指定键值的节点,如果存在则返回该节点的指针,否则返回 `NULL`。 + 6. `InsertNode(HashTableType* hash_table, int key, int value)`:向哈希表中插入一个键值对,如果插入成功则返回 1,否则返回 0。 + 7. `RemoveNode(HashTableType* hash_table, int key)`:从哈希表中删除指定键值的节点,如果删除成功则返回 1,否则返回 0。 + 8. `ModifyNode(HashTableType* hash_table, int key, int value)`:修改哈希表中指定键值的节点的值,如果修改成功则返回 1,否则返回 0。 + 9. `Display(HashTableType* hash_table)`:打印哈希表中所有的键值对。 + 10. `TestHash()`:对哈希表进行一系列测试,包括插入、查找、修改、删除等操作,并输出相应的结果。 + 此程序文件与其他模块或函数的接口关系较少,主要使用了自定义的数据结构类型 `HashTableType` 和 `NodeType`,以及一些标准库函数(如 `malloc` 和 `printf`)。输出值的含义和取值范围在函数中有相应的注释和说明。参数间的控制、顺序、独立或依赖等关系主要由函数的实现决定,例如删除节点前需要先查找节点,修改节点前需要先判断节点是否存在等。函数之间相互独立,可以单独调用,但也可以组合使用。// ⽤于详细说明此程序文件完成的主要功能,与其他模块或函数的接⼝,输出值、取值范围、含义及参数间的控制、顺序、独立或依赖等关系 + Others: V1.0// 其它内容的说明 + History: // 修改历史记录列表,每条修改记录应包括修改⽇期、修改者及修改内容简述 + 1. Date: 2023.7.2 + Author: oscar + Modification: Achieve the intended function. Add and normalize comments. +*************************************************/ + +#include +#include "test_hash.h" + +HashTableType* InitHashTable() { + HashTableType* hash_table = (HashTableType*)malloc(sizeof(HashTableType)); + hash_table->tabel_size = 0; + for (int i = 0; i < MAX_TABLE_SIZE; i++) + hash_table->table[i] = NULL; + return hash_table; +} + +int GetHash(int key) { + return key % MAX_TABLE_SIZE; +} + +NodeType* InitNode(int key, int value) { + NodeType* node = (NodeType*)malloc(sizeof(NodeType)); + node->key = key; + node->value = value; + node->next = NULL; + return node; +} + +int GetTableSize(HashTableType* hash_table) { + return hash_table->tabel_size; +} + +NodeType* FindNode(HashTableType* hash_table, int key) { + int index = GetHash(key); + NodeType* nowNode = hash_table->table[index]; + while (nowNode != NULL) { + if (nowNode->key == key) { + return nowNode; + } + nowNode = nowNode->next; + } + return NULL; +} + +void InsertNode(HashTableType* hash_table, int key, int value) { + if (GetTableSize(hash_table) >= MAX_TABLE_SIZE) { + printf("Fail to insert, HashTableType is full."); + return; + } + + int index = GetHash(key); + if (hash_table->table[index] == NULL) { + NodeType* InsertNode = InitNode(key, value); + hash_table->table[index] = InsertNode; + hash_table->tabel_size++; + } else { + NodeType* nowNode = hash_table->table[index]; + while (nowNode->next != NULL && nowNode->key != key) + nowNode = nowNode->next; + if (nowNode->key == key) { + nowNode->value = value; + } else { + NodeType* InsertNode = InitNode(key, value); + nowNode->next = InsertNode; + hash_table->tabel_size++; + } + } +} + +int RemoveNode(HashTableType* hash_table, int key) { + int index = GetHash(key); + NodeType* nowNode = hash_table->table[index]; + NodeType* preNode = NULL; + + while (nowNode != NULL) { + if (nowNode->key == key) { + if (preNode == NULL) { + hash_table->table[index] = nowNode->next; + } else { + preNode->next = nowNode->next; + } + free(nowNode); + hash_table->tabel_size--; + return 1; + } + preNode = nowNode; + nowNode = nowNode->next; + } + return 0; +} + +int ModifyNode(HashTableType* hash_table, int key, int value) { + if (FindNode(hash_table,key) == 0) + return 0; + int index = GetHash(key); + NodeType* nowNode = hash_table->table[index]; + while (nowNode != NULL) { + if (nowNode->key == key) { + nowNode->value = value; + return 1; + } + nowNode = nowNode->next; + } +} + +void Display(HashTableType* hash_table) { + printf("HashTableType:{"); + for (int i = 0; i < MAX_TABLE_SIZE; i++) { + NodeType* nowNode = hash_table->table[i]; + while (nowNode != NULL) { + printf("(%d, %d),", nowNode->key, nowNode->value); + nowNode = nowNode->next; + } + } + printf("}\n"); +} + +void TestHash() { + HashTableType* hash_table = InitHashTable(); + + //测试增加 + printf("testing add method...\n"); + printf("Add 3 node to hashtable....\n"); + InsertNode(hash_table,2,2); + Display(hash_table); + InsertNode(hash_table,3,3); + Display(hash_table); + InsertNode(hash_table,4,4); + Display(hash_table); + + //测试哈希表满 + printf("\nHashTable maxsize is 3, now insert 4th node, check if success:\n "); + InsertNode(hash_table,14,14); + + //测试查找 + printf("\ntesting find method...\n"); + NodeType* found_node = FindNode(hash_table,4); + printf("find key 4,value is %d\n",found_node->value); + + //测试修改 + printf("\ntesting modify method...\n"); + printf("modify key=2 value=100\n"); + int check_success = ModifyNode(hash_table, 2, 100); + if(check_success == 0) { + printf("modify failed, key not exist.\n"); + } else{ + printf("modify success\n"); + } + found_node = FindNode(hash_table, 2); + printf("verify: (%d %d)\n", found_node->key, found_node->value); + + Display(hash_table); + + // 删除键值对 + printf("\ntesting remove method...\n"); + check_success = RemoveNode(hash_table, 3); + if (check_success == 0) { + printf("key not exist, fail to remove.\n"); + } else { + printf("remove success\n"); + } + found_node = FindNode(hash_table,3); + if (found_node == NULL) { + printf("verify: key 3 is removed\n"); + } + + Display(hash_table); + + return; +} + +PRIV_SHELL_CMD_FUNCTION(TestHash, Implement a simple printf test, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hash/test_hash.h b/APP_Framework/Applications/app_test/test_hash/test_hash.h new file mode 100644 index 000000000..8c7c9526a --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.h @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2023 oscar +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL +v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/************************************************* + File name: tesh_hash.h// 文件名 + Description: 这个头文件定义了一个基于链表的哈希表数据结构。其中: + 1. `NodeType` 结构体表示哈希表中的一个节点,包含了该节点的键值以及指向下一个节点的指针。 + 2. `HashTableType` 结构体表示整个哈希表,包含了一个长度为 `MAX_TABLE_SIZE` 的指针数组 `table`,用于存储节点,并且记录了哈希表中节点的数量 `tabel_size`。 + 该头文件的主要功能是定义了 `NodeType` 和 `HashTableType` 两个自定义的数据类型,为使用基于链表的哈希表提供了便利。可以在需要使用哈希表的代码中包含该头文件,并根据需要创建相应的 `HashTableType` 变量,然后使用其中定义的函数来操作哈希表。例如可以使用 `InitHashTable()` 函数来初始化哈希表,使用 `InsertNode()` 函数来插入一个节点,使用 `FindNode()` 函数来查找指定键值的节点等等。具体使用方法可以参考使用哈希表的代码示例.// ⽤于详细说明此程序文件完成的主要功能,与其他模块或函数的接⼝,输出值、取值范围、含义及参数间的控制、顺序、独立或依赖等关系 + Others: V1.0// 其它内容的说明 + History: // 修改历史记录列表,每条修改记录应包括修改⽇期、修改者及修改内容简述 + 1. Date: 2023.7.2 + Author: oscar + Modification: Achieve the intended function. Add and normalize comments. +*************************************************/ + +#include +#include + +#define MAX_TABLE_SIZE 3 + +typedef struct TableNode { + int key; + int value; + struct TableNode* next; +} NodeType; + +typedef struct HashTable{ + NodeType* table[MAX_TABLE_SIZE]; + int tabel_size; +}HashTableType; \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hash/启动qemu并运行shell命令.png b/APP_Framework/Applications/app_test/test_hash/启动qemu并运行shell命令.png new file mode 100644 index 000000000..84c6afa23 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/启动qemu并运行shell命令.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/打开menuconfig进行裁剪.png b/APP_Framework/Applications/app_test/test_hash/打开menuconfig进行裁剪.png new file mode 100644 index 000000000..543ee2b35 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/打开menuconfig进行裁剪.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/编译项目.png b/APP_Framework/Applications/app_test/test_hash/编译项目.png new file mode 100644 index 000000000..05a70876b Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/编译项目.png differ