From 5675b771010059601fdd47e5b4f889dc31589c9a Mon Sep 17 00:00:00 2001 From: yanglong <2464416786@qq.com> Date: Sat, 17 Jun 2023 21:31:14 +0800 Subject: [PATCH] 2023_open_source_contest_warmup_1st_issue1 --- APP_Framework/Applications/app_test/Kconfig | 6 +- APP_Framework/Applications/app_test/Makefile | 4 + .../Applications/app_test/test_hash/README.md | 301 ++++++++++++++++++ .../Applications/app_test/test_hash/test.png | Bin 0 -> 24000 bytes .../app_test/test_hash/test_hash.c | 260 +++++++++++++++ .../app_test/test_hash/test_hash.h | 74 +++++ run.sh | 7 + 7 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 APP_Framework/Applications/app_test/test_hash/README.md create mode 100644 APP_Framework/Applications/app_test/test_hash/test.png create mode 100644 APP_Framework/Applications/app_test/test_hash/test_hash.c create mode 100644 APP_Framework/Applications/app_test/test_hash/test_hash.h create mode 100755 run.sh diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index 45df5f5d5..ab8a7112e 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -1,9 +1,13 @@ menu "test app" menuconfig USER_TEST bool "Enable application test function " - default n + default y if USER_TEST + menuconfig USER_TEST_HASH + bool "Config test hash" + default y + menuconfig USER_TEST_ADC bool "Config test adc" default n diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 1cf919846..898ff9d9f 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),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..7f26ffc67 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/README.md @@ -0,0 +1,301 @@ +# 热身赛一级赛题1:基于cortex-m3-emulator实现哈希表并测试验证 + +## 1. 简介 +本项目是基于cortex-m3-emulator实现哈希表并测试验证 +test_hash.h定义所需要的宏,结构体,函数声明 +test_hash.c用于实现哈希表的创建、删除、增删改查等具体操作,以及构建测试函数,并且注入到shell中 + +## 2. 数据结构设计说明 +- 通过数组和链表实现哈希表,链地址法解决哈希冲突,默认数组长度TABLE_SIZE,节点数据结构Entry,哈希表数据结构HashTable +```c +/* the size of hash table */ +#define TABLE_SIZE (1024) +/* element of the hash table's chain list */ +struct Entry +{ + char* key; + void* value; + struct Entry* next; + void (*FreeValue)(void*); +}; +/* HashTable */ +typedef struct +{ + struct Entry ** table; +}HashTable; +``` +- 定义哈希表的创建、删除、增删改查 +```c +/* new an instance of HashTable */ +HashTable* HashTableNew(); + +/* +delete an instance of HashTable, +all values are removed auotmatically. +*/ +void HashTableDelete(HashTable* ht); + +/* +add or update a value to ht, +free_value(if not NULL) is called automatically when the value is removed. +return 0 if success, -1 if error occurred. +*/ +int HashTablePut(HashTable* ht, char* key, void* value); +int HashTablePut2(HashTable* ht, char* key, void* value, void(*free_value)(void*)); + +/* get a value indexed by key, return NULL if not found. */ +void* HashTableGet(HashTable* ht, char* key); + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* ht, char* key); +``` +- 实现哈希表的创建、删除、增删改查 +```c +/* constructor of struct Entry */ +static void InitEntry(struct Entry* entry) +{ + entry->key = NULL; + entry->value = NULL; + entry->next = NULL; + entry->FreeValue = NULL; +} + +/* destructor of struct Entry */ +static void FreeEntry(struct Entry* entry) +{ + if (entry){ + if (entry->FreeValue){ + entry->FreeValue(entry->value); + } + free(entry->key); + entry->key = NULL; + free(entry); + } +} + +/* the classic Times33 hash function */ +static unsigned int Hash33(char* key) +{ + unsigned int hash = 0; + while (*key){ + hash = (hash << 5) + hash + *key++; + } + return hash; +} + +/* new a HashTable instance */ +HashTable* HashTableNew() +{ + HashTable* hash_table = malloc(sizeof(HashTable)); + + if (NULL == hash_table){ + HashTableDelete(hash_table); + return NULL; + } + hash_table->table = malloc(sizeof(struct Entry*) * TABLE_SIZE); + if (NULL == hash_table->table){ + HashTableDelete(hash_table); + return NULL; + } + memset(hash_table->table, 0, sizeof(struct Entry*) * TABLE_SIZE); + + return hash_table; +} + +/* delete a HashTable instance */ +void HashTableDelete(HashTable* hash_table) +{ + if (hash_table){ + if (hash_table->table){ + int i = 0; + for (i = 0; i < TABLE_SIZE; i++){ + struct Entry* p = hash_table->table[i]; + struct Entry* q = NULL; + while (p){ + q = p->next; + FreeEntry(p); + p = q; + } + } + free(hash_table->table); + hash_table->table = NULL; + } + free(hash_table); + } +} + +/* insert or update a value indexed by key without FreeValue */ +int HashTablePut(HashTable* hash_table, char* key, void* value) +{ + return HashTablePut2(hash_table,key,value,NULL); +} + +/* insert or update a value indexed by key with FreeValue */ +int HashTablePut2(HashTable* hash_table, char* key, void* value, void(*FreeValue)(void*)) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + char* key_str = malloc(strlen(key) + 1); + if (key_str == NULL){ + return -1; + } + char* value_str = malloc(strlen(value) + 1); + if (value_str == NULL){ + return -1; + } + strcpy(key_str, key); + strcpy(value_str,value); + + while (p){ /* if key is already stroed, update its value */ + if (strcmp(p->key, key) == 0){ + if (p->FreeValue) { + p->FreeValue(p->value); + } + p->value = value_str; + p->FreeValue = FreeValue; + break; + } + prep = p; + p = p->next; + } + + if (p == NULL){ /* if key has not been stored, then add it */ + struct Entry * entry = malloc(sizeof(struct Entry)); + if (NULL == entry){ + free(key_str); + key_str = NULL; + free(value_str); + value_str = NULL; + return -1; + } + InitEntry(entry); + entry->next = NULL; + entry->key = key_str; + entry->value = value_str; + entry->FreeValue = FreeValue; + + if (prep == NULL){ + hash_table->table[i] = entry; + } + else{ + prep->next = entry; + } + } + return 0; +} + +/* get a value indexed by key */ +void* HashTableGet(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + while (p){ + if (strcmp(key, p->key) == 0){ + return p->value; + } + p = p->next; + } + return NULL; +} + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + while (p){ + if (strcmp(key, p->key) == 0) { + FreeEntry(p); + if (p == prep) { + hash_table->table[i] = NULL; + } + else { + prep->next = p->next; + } + } + prep = p; + p = p->next; + } +} +``` +## 3. 测试程序说明 +- 测试哈希表的基本操作 +```c +/* the test order menu */ +void ShowMenu() +{ + printf("================order menu================\n"); + printf("==========0:insert(TestHash 0 x 2)========\n"); + printf("==========1:get(TestHash 1 x)=============\n"); + printf("==========2:update(TestHash 2 x 1)========\n"); + printf("==========3:remove(TestHash 3 x)==========\n"); +} + +HashTable* hash_table = NULL; +/* test for hash table*/ +void TestHash(int argc, char* argv[]) +{ + if (argc == 1){ + printf("please use TestHash help to check orders\n"); + return; + } + if (strcmp(argv[1],"help") == 0) ShowMenu(); + + if (strcmp(argv[1],"0") == 0){ // insert + if(hash_table == NULL){ + hash_table = HashTableNew(); + } + HashTablePut(hash_table,argv[2],argv[3]); + char* value = (char*)HashTableGet(hash_table,argv[2]); + printf("insert key=%s,val=%s; sucessful!\n",argv[2],value); + }else if (strcmp(argv[1],"1") == 0){ // get + if(hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s)\n",argv[2]); + }else{ + printf("get key=%s,value=%s; answer=%s\n",argv[2],value,value); + } + }else if (strcmp(argv[1],"2") == 0){ // update + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s). please insert first.\n",argv[2]); + }else{ + HashTablePut(hash_table,argv[2],argv[3]); + printf("update key=%s,old_value=%s,value=%s; sucessful\n",argv[2],value,argv[3]); + } + }else if (strcmp(argv[1],"3") == 0){ // remove + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + HashTableRemove(hash_table,argv[2]); + printf("remove key=%s; sucessful!\n",argv[2]); + } + return; +} +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +``` + +## 4. 运行结果(##需结合运行测试截图按步骤说明##) +1. 输入help查看letter shell可以调用的命令 +2. 输入TestHash命令,提示用TestHash help查看TestHash的命令 +3. 没有插入元素就查看元素:TestHash 1 x --> 哈希表为空,提示先插入 +4. 没有插入就删除元素:TestHash 3 x --> 哈希表为空,提示先插入 +5. 插入x=2: TestHash 0 x 2 +6. 查找x: TestHash 1 x +7. 更新x=100: TestHash 2 x 100 +8. 查找更新后的x: TestHash 1 x +9. 删除x: TestHash 3 x +10. 确认是否被删除: TestHash 1 x +![](./test.png) \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hash/test.png b/APP_Framework/Applications/app_test/test_hash/test.png new file mode 100644 index 0000000000000000000000000000000000000000..d803627731685ce526d4e086fe22ae3f2214ea4c GIT binary patch literal 24000 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 +#include +#include +#include + +#ifdef ADD_XIZI_FETURES + +/* constructor of struct Entry */ +static void InitEntry(struct Entry* entry) +{ + entry->key = NULL; + entry->value = NULL; + entry->next = NULL; + entry->FreeValue = NULL; +} + +/* destructor of struct Entry */ +static void FreeEntry(struct Entry* entry) +{ + if (entry){ + if (entry->FreeValue){ + entry->FreeValue(entry->value); + } + free(entry->key); + entry->key = NULL; + free(entry); + } +} + +/* the classic Times33 hash function */ +static unsigned int Hash33(char* key) +{ + unsigned int hash = 0; + while (*key){ + hash = (hash << 5) + hash + *key++; + } + return hash; +} + +/* new a HashTable instance */ +HashTable* HashTableNew() +{ + HashTable* hash_table = malloc(sizeof(HashTable)); + + if (NULL == hash_table){ + HashTableDelete(hash_table); + return NULL; + } + hash_table->table = malloc(sizeof(struct Entry*) * TABLE_SIZE); + if (NULL == hash_table->table){ + HashTableDelete(hash_table); + return NULL; + } + memset(hash_table->table, 0, sizeof(struct Entry*) * TABLE_SIZE); + + return hash_table; +} + +/* delete a HashTable instance */ +void HashTableDelete(HashTable* hash_table) +{ + if (hash_table){ + if (hash_table->table){ + int i = 0; + for (i = 0; i < TABLE_SIZE; i++){ + struct Entry* p = hash_table->table[i]; + struct Entry* q = NULL; + while (p){ + q = p->next; + FreeEntry(p); + p = q; + } + } + free(hash_table->table); + hash_table->table = NULL; + } + free(hash_table); + } +} + +/* insert or update a value indexed by key without FreeValue */ +int HashTablePut(HashTable* hash_table, char* key, void* value) +{ + return HashTablePut2(hash_table,key,value,NULL); +} + +/* insert or update a value indexed by key with FreeValue */ +int HashTablePut2(HashTable* hash_table, char* key, void* value, void(*FreeValue)(void*)) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + char* key_str = malloc(strlen(key) + 1); + if (key_str == NULL){ + return -1; + } + char* value_str = malloc(strlen(value) + 1); + if (value_str == NULL){ + return -1; + } + strcpy(key_str, key); + strcpy(value_str,value); + + while (p){ /* if key is already stroed, update its value */ + if (strcmp(p->key, key) == 0){ + if (p->FreeValue) { + p->FreeValue(p->value); + } + p->value = value_str; + p->FreeValue = FreeValue; + break; + } + prep = p; + p = p->next; + } + + if (p == NULL){ /* if key has not been stored, then add it */ + struct Entry * entry = malloc(sizeof(struct Entry)); + if (NULL == entry){ + free(key_str); + key_str = NULL; + free(value_str); + value_str = NULL; + return -1; + } + InitEntry(entry); + entry->next = NULL; + entry->key = key_str; + entry->value = value_str; + entry->FreeValue = FreeValue; + + if (prep == NULL){ + hash_table->table[i] = entry; + } + else{ + prep->next = entry; + } + } + return 0; +} + +/* get a value indexed by key */ +void* HashTableGet(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + while (p){ + if (strcmp(key, p->key) == 0){ + return p->value; + } + p = p->next; + } + return NULL; +} + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + while (p){ + if (strcmp(key, p->key) == 0) { + FreeEntry(p); + if (p == prep) { + hash_table->table[i] = NULL; + } + else { + prep->next = p->next; + } + } + prep = p; + p = p->next; + } +} + +/* the test order menu */ +void ShowMenu() +{ + printf("================order menu================\n"); + printf("==========0:insert(TestHash 0 x 2)========\n"); + printf("==========1:get(TestHash 1 x)=============\n"); + printf("==========2:update(TestHash 2 x 1)========\n"); + printf("==========3:remove(TestHash 3 x)==========\n"); +} + +HashTable* hash_table = NULL; +/* test for hash table*/ +void TestHash(int argc, char* argv[]) +{ + if (argc == 1){ + printf("please use TestHash help to check orders\n"); + return; + } + if (strcmp(argv[1],"help") == 0) ShowMenu(); + + if (strcmp(argv[1],"0") == 0){ // insert + if(hash_table == NULL){ + hash_table = HashTableNew(); + } + HashTablePut(hash_table,argv[2],argv[3]); + char* value = (char*)HashTableGet(hash_table,argv[2]); + printf("insert key=%s,val=%s; sucessful!\n",argv[2],value); + }else if (strcmp(argv[1],"1") == 0){ // get + if(hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s)\n",argv[2]); + }else{ + printf("get key=%s,value=%s; answer=%s\n",argv[2],value,value); + } + }else if (strcmp(argv[1],"2") == 0){ // update + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s). please insert first.\n",argv[2]); + }else{ + HashTablePut(hash_table,argv[2],argv[3]); + printf("update key=%s,old_value=%s,value=%s; sucessful\n",argv[2],value,argv[3]); + } + }else if (strcmp(argv[1],"3") == 0){ // remove + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + HashTableRemove(hash_table,argv[2]); + printf("remove key=%s; sucessful!\n",argv[2]); + } + return; +} +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +#endif \ 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..2dd3eace4 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* 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 test_hash.h + * @brief a application of hash table + * @version 1.0 + * @author bdislab_final + * @date 2023/6/17 + */ + +#ifndef TEST_HASH_H +#define TEST_HASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* the size of hash table */ +#define TABLE_SIZE (1024) + +/* element of the hash table's chain list */ +struct Entry +{ + char* key; + void* value; + struct Entry* next; + void (*FreeValue)(void*); +}; + +/* HashTable */ +typedef struct +{ + struct Entry ** table; +}HashTable; + + +/* new an instance of HashTable */ +HashTable* HashTableNew(); + +/* +delete an instance of HashTable, +all values are removed auotmatically. +*/ +void HashTableDelete(HashTable* ht); + +/* +add or update a value to ht, +free_value(if not NULL) is called automatically when the value is removed. +return 0 if success, -1 if error occurred. +*/ +int HashTablePut(HashTable* ht, char* key, void* value); +int HashTablePut2(HashTable* ht, char* key, void* value, void(*free_value)(void*)); + +/* get a value indexed by key, return NULL if not found. */ +void* HashTableGet(HashTable* ht, char* key); + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* ht, char* key); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 000000000..95221430e --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd /home/yanglong/Desktop/xiuos/xiuos/Ubiquitous/XiZi_IIoT +make BOARD=cortex-m3-emulator distclean +make BOARD=cortex-m3-emulator menuconfig +make BOARD=cortex-m3-emulator +sleep +qemu-system-arm -machine lm3s6965evb -nographic -kernel build/XiZi-cortex-m3-emulator.elf \ No newline at end of file