Commit 热身赛一级赛题3
| 
						 | 
					@ -240,5 +240,9 @@ menu "test app"
 | 
				
			||||||
                bool "Config test soft timer"
 | 
					                bool "Config test soft timer"
 | 
				
			||||||
                default n
 | 
					                default n
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
					            menuconfig USER_TEST_RADIX
 | 
				
			||||||
 | 
					                bool "Config test radix tree"
 | 
				
			||||||
 | 
					                default n
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
        endif
 | 
					        endif
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,5 +101,9 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
 | 
				
			||||||
        SRC_FILES += test_timer.c
 | 
					        SRC_FILES += test_timer.c
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ifeq ($(CONFIG_USER_TEST_RADIX),y)
 | 
				
			||||||
 | 
					        SRC_FILES += test_radix_tree/test_radix_tree.c
 | 
				
			||||||
 | 
					    endif    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    include $(KERNEL_ROOT)/compiler.mk
 | 
					    include $(KERNEL_ROOT)/compiler.mk
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					# 基数树
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 代码实现
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					基数树节点设计为:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```C
 | 
				
			||||||
 | 
					typedef struct _node {
 | 
				
			||||||
 | 
					    void* value;
 | 
				
			||||||
 | 
					    struct _node* next[NODE_SIZE];
 | 
				
			||||||
 | 
					} node;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					其中,`NODE_SIZE` 定义为 128,足以容纳所有 ASCII 值。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					一共实现了 5 个函数,分别为:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `CreateNode`:创建一个基数树节点
 | 
				
			||||||
 | 
					- `InsertNode`:将一对键值对插入基数树
 | 
				
			||||||
 | 
					- `DeleteNode`:删除指定键的键值对
 | 
				
			||||||
 | 
					- `FindNode`:查找指定键对应的值
 | 
				
			||||||
 | 
					- `DestroyTree`:销毁整个基数树
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 程序测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					测试程序 `TestRadix` 已经注册为 shell 命令,可以调用执行。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					测试程序定义了以下键值对:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					char keys[][MAX_WORD_LEN] = {
 | 
				
			||||||
 | 
					    "what",
 | 
				
			||||||
 | 
					    "where",
 | 
				
			||||||
 | 
					    "why",
 | 
				
			||||||
 | 
					    "how",
 | 
				
			||||||
 | 
					    "hello!",
 | 
				
			||||||
 | 
					    "apple",
 | 
				
			||||||
 | 
					    "12345"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					int values[] = {1, 2, 3, 4, 5, 6, 7};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 程序的第一部分创建了基数树,并且将定义的 7 个键值对的前 6 个插入了基数树,然后分别查找 7 个键,前 6 个均可以找到对应的值,最后一个未插入,因此无法找到
 | 
				
			||||||
 | 
					2. 程序的第二部分从基数树中删除了 `where` 和 `how` 两个键,再次分别查找 7 个键,删除的键值对和未插入的键值对均无法找到
 | 
				
			||||||
 | 
					3. 程序的第三部分重新插入了已删除的 `where` 和未插入过的 `12345` ,再次分别查找 7 个键,新插入的值可以检索到
 | 
				
			||||||
 | 
					4. 程序的第四部分将基数树销毁,再次分别查找 7 个键,所有的键值对均无法找到
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 流程记录
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 在工作区终端中输入命令:`make BOARD=k210-emulator menuconfig`,进入配置页面
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. 依次进入 `APP_Framework` -> `Applications` -> `test app` 目录,将 `Enable application test function` 选项置为 `Y`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. 进入 `Enable application test function` 将 `Config test radix tree` 选项置为 `Y`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. 一直选择 `Exit` 退出配置,在最后需要确认的页面选择 `Yes` 保存配置
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. 执行编译命令:`make BOARD=k210-emulator`,正常情况下应当编译无误
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					6. 在 `qemu` 中运行:`qemu-system-riscv64 -nographic -machine sifive_u -bios build/XiZi-k210-emulator.elf`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					7. 在 shell 中运行命令 `TestRadix`,执行结果与预期一致,验证完成。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 After Width: | Height: | Size: 71 KiB  | 
| 
		 After Width: | Height: | Size: 131 KiB  | 
| 
		 After Width: | Height: | Size: 32 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 61 KiB  | 
| 
		 After Width: | Height: | Size: 238 KiB  | 
| 
						 | 
					@ -0,0 +1,194 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_radix_tree.c
 | 
				
			||||||
 | 
					* @brief:   Implement a simple radix tree
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @date:    2023/5/24
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NODE_SIZE 128
 | 
				
			||||||
 | 
					#define MAX_WORD_LEN 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _node {
 | 
				
			||||||
 | 
					    void* value;
 | 
				
			||||||
 | 
					    struct _node* next[NODE_SIZE];
 | 
				
			||||||
 | 
					} node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description: Create a radix tree node
 | 
				
			||||||
 | 
					 * @return node pointer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					node* CreateNode()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    node* n = (node*)malloc(sizeof(node));
 | 
				
			||||||
 | 
					    n->value = NULL;
 | 
				
			||||||
 | 
					    for (int i = 0; i < NODE_SIZE; i++) {
 | 
				
			||||||
 | 
					        n->next[i] = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description: Insert a new node to radix tree
 | 
				
			||||||
 | 
					 * @param root - radix tree root
 | 
				
			||||||
 | 
					 * @param key - new node key
 | 
				
			||||||
 | 
					 * @param value - new node value
 | 
				
			||||||
 | 
					 * @return void
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void InsertNode(node* root, const char* key, void* value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (root == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    node* cur = root;
 | 
				
			||||||
 | 
					    size_t len = strlen(key);
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        uint8_t b = (uint8_t)key[i];
 | 
				
			||||||
 | 
					        if (cur->next[b] == NULL) {
 | 
				
			||||||
 | 
					            cur->next[b] = CreateNode();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cur = cur->next[b];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cur->value = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description: Delete a node from radix tree
 | 
				
			||||||
 | 
					 * @param root - radix tree root
 | 
				
			||||||
 | 
					 * @param key - key which is needed to delete
 | 
				
			||||||
 | 
					 * @return void
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void DeleteNode(node* root, const char* key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (root == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    node** cur = &root;
 | 
				
			||||||
 | 
					    size_t len = strlen(key);
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        uint8_t b = (uint8_t)key[i];
 | 
				
			||||||
 | 
					        if ((*cur)->next[b] == NULL) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cur = &((*cur)->next[b]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((*cur)->value == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (*cur)->value = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int has_children = 0;
 | 
				
			||||||
 | 
					    for (int i = 0; i < NODE_SIZE; i++) {
 | 
				
			||||||
 | 
					        if ((*cur)->next[i] != NULL) {
 | 
				
			||||||
 | 
					            has_children = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!has_children) {
 | 
				
			||||||
 | 
					        free(*cur);
 | 
				
			||||||
 | 
					        (*cur) = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description: find a node by key
 | 
				
			||||||
 | 
					 * @param root - radix tree root
 | 
				
			||||||
 | 
					 * @param key - key which is needed to find
 | 
				
			||||||
 | 
					 * @return value pointer corresponding to key
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void* FindNode(node* root, const char* key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (root == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    node* cur = root;
 | 
				
			||||||
 | 
					    size_t len = strlen(key);
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        uint8_t b = (uint8_t)key[i];
 | 
				
			||||||
 | 
					        if (cur->next[b] == NULL) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cur = cur->next[b];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return cur->value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description: Destroy the radix tree
 | 
				
			||||||
 | 
					 * @param root - radix tree root
 | 
				
			||||||
 | 
					 * @return void
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void DestroyTree(node* root)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (root == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (int i = 0; i < NODE_SIZE; i++) {
 | 
				
			||||||
 | 
					        DestroyTree(root->next[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(root);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TestRadix()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char keys[][MAX_WORD_LEN] = {
 | 
				
			||||||
 | 
					        "what",
 | 
				
			||||||
 | 
					        "where",
 | 
				
			||||||
 | 
					        "why",
 | 
				
			||||||
 | 
					        "how",
 | 
				
			||||||
 | 
					        "hello!",
 | 
				
			||||||
 | 
					        "apple",
 | 
				
			||||||
 | 
					        "12345"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    int values[] = {1, 2, 3, 4, 5, 6, 7};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\nCreate tree and add key & value:\n");
 | 
				
			||||||
 | 
					    node* root = CreateNode();
 | 
				
			||||||
 | 
					    if (!root) printf("Create node failed.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int num = sizeof(keys) / sizeof(keys[0]);
 | 
				
			||||||
 | 
					    for (int i = 0; i < num - 1; ++i) {
 | 
				
			||||||
 | 
					        InsertNode(root, keys[i], &values[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
					        int* v = (int*)FindNode(root, keys[i]);
 | 
				
			||||||
 | 
					        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
				
			||||||
 | 
					        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\nDelete \"where\" and \"how\":\n");
 | 
				
			||||||
 | 
					    DeleteNode(root, keys[1]);
 | 
				
			||||||
 | 
					    DeleteNode(root, keys[3]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for (int i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
					        int* v = (int*)FindNode(root, keys[i]);
 | 
				
			||||||
 | 
					        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
				
			||||||
 | 
					        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\nInsert \"where\" and \"12345\":\n");
 | 
				
			||||||
 | 
					    InsertNode(root, keys[1], &values[1]);
 | 
				
			||||||
 | 
					    InsertNode(root, keys[6], &values[6]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
					        int* v = (int*)FindNode(root, keys[i]);
 | 
				
			||||||
 | 
					        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
				
			||||||
 | 
					        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\nDestroy tree:\n");
 | 
				
			||||||
 | 
					    DestroyTree(root);
 | 
				
			||||||
 | 
					    root = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
					        int* v = (int*)FindNode(root, keys[i]);
 | 
				
			||||||
 | 
					        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
				
			||||||
 | 
					        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestRadix, Implement a simple radix tree, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||