2023_open_source_contest_warmup_1st_issue1
This commit is contained in:
parent
7754a149a9
commit
a03f6de225
|
@ -1,9 +1,13 @@
|
|||
menu "test app"
|
||||
menuconfig USER_TEST
|
||||
bool "Enable application test function "
|
||||
default n
|
||||
default y
|
||||
|
||||
if USER_TEST
|
||||
menuconfig USER_HASH_TABLE
|
||||
bool "Config test hash table"
|
||||
default y
|
||||
|
||||
menuconfig USER_TEST_ADC
|
||||
bool "Config test adc"
|
||||
default n
|
||||
|
|
|
@ -25,6 +25,10 @@ endif
|
|||
ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||
SRC_FILES := test_shell.c
|
||||
|
||||
ifeq ($(CONFIG_USER_HASH_TABLE),y)
|
||||
SRC_FILES += test_hash/test_hash.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_ADC),y)
|
||||
SRC_FILES += test_adc.c
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
# 热身赛一级赛题1:基于cortex-m3-emulator实现哈希表并测试验证
|
||||
|
||||
[toc]
|
||||
|
||||
参赛战队:bdislab_0
|
||||
赛题issue:热身赛一级赛题1
|
||||
完成情况:实现哈希表,支持链地址法解决哈希冲突。
|
||||
|
||||
## 1. 简介:注册shell命令以及哈希命令集说明
|
||||
**0. 注册TestHashTable命令**
|
||||
源文件见:APP_Framework/Applications/app_test/test_hash/test_hash.c
|
||||
|
||||
**1. 插入(key, value)对**
|
||||
```
|
||||
TestHashTable 1 key value
|
||||
```
|
||||
说明:
|
||||
- 当插入的key不存在时,返回 success。
|
||||
- 当插入的key已经存在时,新值value会覆盖旧值。
|
||||
- 注意:key支持`int`或`string`等若干类型数值,但value仅支持`int`范围内的数值。
|
||||
|
||||
|
||||
**2. 查询key对应的(key, value)对**
|
||||
```
|
||||
TestHashTable 2 key value
|
||||
```
|
||||
说明:
|
||||
- 当查询的key存在时,输出对应的(key, value)对。
|
||||
- 当查询的key不存在时,返回 not exist。
|
||||
|
||||
|
||||
**3. 删除key对应的(key, value)对**
|
||||
```
|
||||
TestHashTable 3 key value
|
||||
```
|
||||
说明:
|
||||
- 当删除的key存在时,删除对应的(key, value)对。
|
||||
- 当删除的key不存在时,返回 not exist。
|
||||
|
||||
**4. 执行帮助**
|
||||
```
|
||||
TestHashTable help
|
||||
```
|
||||
输出指令集帮助。
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
|
||||
首先,设计了一个结构体 `struct Hash_entry` 表示每一项哈希结构,字段如下:包含原始的key变量(字符串类型的okey),哈希后的key变量(int类型的key),和value变量。
|
||||
```
|
||||
struct Hash_entry {
|
||||
char *okey;
|
||||
int key;
|
||||
int val;
|
||||
struct Hash_entry *next;
|
||||
struct Hash_entry *prev;
|
||||
};
|
||||
```
|
||||
|
||||
第二,哈希的模数为MOD。通过拉链法解决哈希冲突,所以定义了MOD个哈希链表的头,即`struct Hash_entry *hts[MOD]`。并定义了一个数组记录每种哈希值对应链表的长度,即`int htlen[MOD]`。
|
||||
|
||||
第三,获取哈希值的函数:`int get_hash_val(char *okey)`。
|
||||
|
||||
第四,插入:`int insert_kv(char *okey, char *val)`。
|
||||
|
||||
第五,查询:`int query_key(char *okey)`。
|
||||
|
||||
第六,删除:`int delete_key(char *okey)`。
|
||||
|
||||
## 3. 测试程序说明
|
||||
|
||||
测试结果,打印验证功能:均正确。
|
||||
|
||||
## 4. 运行结果:测试流程及截图
|
||||
|
||||
注意:key支持`int`或`string`等若干类型数值,但value仅支持`int`范围内的数值。
|
||||
|
||||
测试流程:
|
||||
1. 首先查看哈希表指令集执行帮助:`TestHashTable help`
|
||||
2. 插入(1, 1)对:`TestHashTable 1 1 1`,插入成功返回success
|
||||
3. 重复插入(1, 2)对:`TestHashTable 1 1 2`,新值2覆盖旧值1
|
||||
4. 查询2对应的(key, value)对:`TestHashTable 2 2`,返回not exist
|
||||
5. 查询1对应的(key, value)对:`TestHashTable 2 1`,输出key(1), value(2)
|
||||
6. 删除1对应的(key, value)对:`TestHashTable 3 1`,删除成功返回success
|
||||
7. 查询1对应的(key, value)对:`TestHashTable 2 1`,返回not exist
|
||||
8. 插入(1, 10)对:`TestHashTable 1 1 10`,插入成功返回success
|
||||
9. 查询1对应的(key, value)对:`TestHashTable 2 1`,输出key(1), value(10)
|
||||
|
||||
测试截图:
|
||||

|
||||
|
||||
总结:注册shell命令,打印验证功能均正确。
|
||||
|
||||
## 附录
|
||||
|
||||
修改/新增的文件列表:
|
||||
```
|
||||
APP_Framework/Applications/app_test/Kconfig
|
||||
APP_Framework/Applications/app_test/Makefile
|
||||
APP_Framework/Applications/app_test/test_hash/
|
||||
APP_Framework/Applications/app_test/test_hash/README.md
|
||||
APP_Framework/Applications/app_test/test_hash/test_hash.c
|
||||
APP_Framework/Applications/app_test/test_hash/evaluation.png
|
||||
```
|
||||
|
||||
赛题链接: https://www.gitlink.org.cn/xuos/xiuos/issues/261
|
||||
|
||||
提交指南: https://www.gitlink.org.cn/competitions/index/track1_2023_xiuos
|
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* 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.c
|
||||
* @brief: a application of hash function
|
||||
* @version: 2.0
|
||||
* @author: XiUOS Team: bdislab_0
|
||||
* @date: 2023/6/5
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
#include "test_hash.h"
|
||||
|
||||
/**
|
||||
* @brief Priv-shell Command definition
|
||||
*
|
||||
* @param _func Command function
|
||||
* @param _desc Command description
|
||||
* @param _attr Command attributes if need
|
||||
*/
|
||||
#define PRIV_SHELL_CMD_FUNCTION(_func, _desc, _attr) SHELL_EXPORT_CMD(_attr, _func, _func, _desc)
|
||||
|
||||
|
||||
struct Hash_entry *create_hash_entry(char *okey_, int key_, int val_) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Hash_entry *hts[MOD];
|
||||
int htlen[MOD];
|
||||
|
||||
int get_hash_val(char *okey) {
|
||||
int ans = 0;
|
||||
while(*okey) {
|
||||
ans = (ans * 233 + *okey) % MOD;
|
||||
okey ++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
char * str_copy(char *s, char *t) {
|
||||
int len = strlen(t) + 1;
|
||||
s = (char *)malloc(len);
|
||||
for(int i = 0; i < len; ++i) s[i] = t[i];
|
||||
s[len] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
void insert_tail(struct Hash_entry *head, struct Hash_entry *last, struct Hash_entry *tmp) {
|
||||
last->next = tmp;
|
||||
tmp->next = head;
|
||||
tmp->prev = last;
|
||||
head->prev = tmp;
|
||||
}
|
||||
|
||||
int str_to_int(char *str) {
|
||||
int ans = 0;
|
||||
while(*str) {
|
||||
ans = (ans * 10 + *str - '0');
|
||||
str ++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
int insert_kv(char *okey, char *val) {
|
||||
int key = get_hash_val(okey);
|
||||
int ret = NOT_EXIST_VAL;
|
||||
if(htlen[key] == 0) {
|
||||
hts[key] = (struct Hash_entry *)malloc(sizeof(struct Hash_entry));
|
||||
hts[key]->prev = hts[key];
|
||||
hts[key]->next = hts[key];
|
||||
hts[key]->okey = str_copy(hts[key]->okey, okey);
|
||||
hts[key]->key = key;
|
||||
hts[key]->val = str_to_int(val);
|
||||
// printf("insert_kv: %p %s %d %d\n", hts[key], hts[key]->okey, key, hts[key]->val);
|
||||
htlen[key] += 1;
|
||||
return ret;
|
||||
}else {
|
||||
struct Hash_entry *head = hts[key];
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
ret = head->val;
|
||||
head->val = str_to_int(val);
|
||||
}else {
|
||||
head = head->next;
|
||||
while(head != hts[key]) {
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
ret = head->val;
|
||||
head->val = str_to_int(val);
|
||||
break;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
if(ret != NOT_EXIST_VAL) {
|
||||
return ret;
|
||||
}
|
||||
struct Hash_entry *new_he = (struct Hash_entry *)malloc(sizeof(struct Hash_entry));
|
||||
new_he->prev = new_he;
|
||||
new_he->next = new_he;
|
||||
new_he->okey = str_copy(new_he->okey, okey);
|
||||
new_he->key = key;
|
||||
new_he->val = str_to_int(val);
|
||||
insert_tail(hts[key], hts[key]->prev, new_he);
|
||||
htlen[key] += 1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int query_key(char *okey) {
|
||||
int val = NOT_EXIST_VAL;
|
||||
int key = get_hash_val(okey);
|
||||
if(htlen[key] != 0) {
|
||||
struct Hash_entry *head = hts[key];
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
val = head->val;
|
||||
}else {
|
||||
head = head->next;
|
||||
while(head != hts[key]) {
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
val = head->val;
|
||||
break;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int delete_key(char *okey) {
|
||||
int ret = NOT_EXIST_VAL;
|
||||
int key = get_hash_val(okey);
|
||||
if(htlen[key] != 0) {
|
||||
struct Hash_entry *head = hts[key];
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
ret = head->val;
|
||||
struct Hash_entry * le = head->prev, *ri = head->next;
|
||||
le->next = ri;
|
||||
ri->prev = le;
|
||||
hts[key] = ri;
|
||||
free(head->okey);
|
||||
free(head);
|
||||
htlen[key] -= 1;
|
||||
}else {
|
||||
head = head->next;
|
||||
while(head != hts[key]) {
|
||||
if(strcmp(head->okey, okey) == 0) {
|
||||
ret = head->val;
|
||||
struct Hash_entry * le = head->prev, *ri = head->next;
|
||||
le->next = ri;
|
||||
ri->prev = le;
|
||||
// hts[key] = ri;
|
||||
free(head->okey);
|
||||
free(head);
|
||||
htlen[key] -= 1;
|
||||
break;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TestHashTable(int argc, char *argv[])
|
||||
{
|
||||
printf("%d parameter(s): ", argc);
|
||||
for (char i = 1; i < argc; i++) {
|
||||
printf("%s ", argv[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
if(argc == 4 && argv[1][0] == '1') {// x.c 1 key val
|
||||
int val = insert_kv(argv[2], argv[3]);
|
||||
if(val == NOT_EXIST_VAL) {
|
||||
printf("insert key (%s), val (%s) success\n", argv[2], argv[3]);
|
||||
}else {
|
||||
printf("insert key (%s), val (%s) repeat, old value (%d) is overwritten\n", argv[2], argv[3], 1);
|
||||
}
|
||||
}else if(argc == 3 && argv[1][0] == '2') {// x.c 2 key
|
||||
int val = query_key(argv[2]);
|
||||
if(val == NOT_EXIST_VAL) {
|
||||
printf("query key(%s), not exist\n", argv[2]);
|
||||
}else {
|
||||
printf("query key(%s), answer: %d\n", argv[2], val);
|
||||
}
|
||||
}else if(argc == 3 && argv[1][0] == '3') {// x.c 3 key
|
||||
// del
|
||||
int val = delete_key(argv[2]);
|
||||
if(val == NOT_EXIST_VAL) {
|
||||
printf("delete key(%s), not exist\n", argv[2]);
|
||||
}else {
|
||||
printf("delete key(%s), val(%d) success\n", argv[2], val);
|
||||
}
|
||||
}else if(argc == 2 && argv[1][0] == 'h') {// x.c help
|
||||
// help
|
||||
printf("TestHashTable help:\n");
|
||||
printf("- 1 key val: insert (key, val), duplicate keys will overwrite old values. Only `int` range data is supported\n");
|
||||
printf("- 2 key: query key\n");
|
||||
printf("- 3 key: delete key\n");
|
||||
printf("- help: help\n");
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(TestHashTable, a hashtable sample, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
|
||||
|
||||
// int main() {
|
||||
// int n;
|
||||
// int opt;
|
||||
// char key[55], val[55];
|
||||
// printf("input opertion numbers:\n");
|
||||
// scanf("%d", &n);
|
||||
// while(n --) {
|
||||
// printf("\ninput opertion:\n");
|
||||
// scanf("%d", &opt);
|
||||
// if(opt == 1) {
|
||||
// scanf("%s%s", key, val);
|
||||
// int ret = insert_kv(key, val);
|
||||
// printf("insert key: %s, val: %s, ret: %d\n", key, val, ret);
|
||||
// }else if(opt == 2) {
|
||||
// scanf("%s", key);
|
||||
// int val = query_key(key);
|
||||
// printf("query key: %s, answer: %d\n", key, val);
|
||||
// }else if(opt == 3) {
|
||||
// scanf("%s", key);
|
||||
// int val = delete_key(key);
|
||||
// printf("query key: %s, answer: %d\n", key, val);
|
||||
// }
|
||||
// else {
|
||||
// printf("error opt\n");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
/*
|
||||
gcc test_hash.c
|
||||
./a.out
|
||||
12
|
||||
1 10 10
|
||||
2 10
|
||||
|
||||
|
||||
1 1 1
|
||||
1 1 2
|
||||
2 2
|
||||
2 1
|
||||
3 1
|
||||
2 1
|
||||
1 1 10
|
||||
2 1
|
||||
|
||||
*/
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const int INF = 0x3f3f3f3f;
|
||||
|
||||
#define MOD (1000 + 5)
|
||||
#define NOT_EXIST_VAL (-INF)
|
||||
|
||||
struct Hash_entry {
|
||||
char *okey;
|
||||
int key;
|
||||
int val;
|
||||
struct Hash_entry *next;
|
||||
struct Hash_entry *prev;
|
||||
};
|
Loading…
Reference in New Issue