2023_open_source_contest_warmup_1st_issue1
This commit is contained in:
parent
7754a149a9
commit
a03f6de225
|
@ -1,9 +1,13 @@
|
||||||
menu "test app"
|
menu "test app"
|
||||||
menuconfig USER_TEST
|
menuconfig USER_TEST
|
||||||
bool "Enable application test function "
|
bool "Enable application test function "
|
||||||
default n
|
default y
|
||||||
|
|
||||||
if USER_TEST
|
if USER_TEST
|
||||||
|
menuconfig USER_HASH_TABLE
|
||||||
|
bool "Config test hash table"
|
||||||
|
default y
|
||||||
|
|
||||||
menuconfig USER_TEST_ADC
|
menuconfig USER_TEST_ADC
|
||||||
bool "Config test adc"
|
bool "Config test adc"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -25,6 +25,10 @@ endif
|
||||||
ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||||
SRC_FILES := test_shell.c
|
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)
|
ifeq ($(CONFIG_USER_TEST_ADC),y)
|
||||||
SRC_FILES += test_adc.c
|
SRC_FILES += test_adc.c
|
||||||
endif
|
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