热身赛一级赛题3
This commit is contained in:
parent
7754a149a9
commit
8e06261da6
|
@ -240,5 +240,8 @@ menu "test app"
|
|||
bool "Config test soft timer"
|
||||
default n
|
||||
|
||||
menuconfig USER_TEST_HASH
|
||||
bool "Config test hash table"
|
||||
default n
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -99,6 +99,10 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
|||
|
||||
ifeq ($(CONFIG_USER_TEST_TIMER),y)
|
||||
SRC_FILES += test_timer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_HASH),y)
|
||||
SRC_FILES += test_hash/test_hash.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
Binary file not shown.
After Width: | Height: | Size: 309 KiB |
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
Binary file not shown.
After Width: | Height: | Size: 346 KiB |
|
@ -0,0 +1,74 @@
|
|||
# 哈希表
|
||||
|
||||
## 1. 简介
|
||||
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
哈希表节点元素及哈希表设计如下:
|
||||
```
|
||||
typedef struct kv
|
||||
{
|
||||
struct kv* next;
|
||||
char* key;
|
||||
void* value;
|
||||
}kv;
|
||||
|
||||
/* HashTable */
|
||||
typedef struct HashTable
|
||||
{
|
||||
struct kv ** table;
|
||||
}HashTable;
|
||||
```
|
||||
其中,一共实现了8个函数,分别为:
|
||||
- `init_kv`:构造一个哈希表节点并初始化
|
||||
- `free_kv`:删除一个哈希表节点
|
||||
- `hash_33`:经典Times33哈希函数
|
||||
- `hash_table_delete`:销毁一个哈希表
|
||||
- `hash_table_new`:构造一个哈希表并初始化
|
||||
- `hash_table_put2`:根据key插入或更新value
|
||||
- `hash_table_get`:根据key获取value
|
||||
- `hash_table_rm`:根据key移除一个键值对
|
||||
## 3. 测试程序说明
|
||||
测试程序 `TestHash` 已经注册为 shell 命令,可以调用执行。
|
||||
|
||||
测试程序定义了以下键值对:
|
||||
```
|
||||
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 个键,所有的键值对均无法找到
|
||||
|
||||
|
||||
## 4. 运行结果(需结合运行测试截图按步骤说明)
|
||||
1.在工作区终端中输入命令,进入配置页面
|
||||
```
|
||||
cd /xiuos/Ubiquitous/XiZi_IIoT
|
||||
make BOARD=cortex-m3-emulator menuconfig
|
||||
```
|
||||

|
||||
2.依次进入 `APP_Framework` -> `Applications` -> `test app` 目录,将 `Enable application test function` 选项置为 `Y`
|
||||

|
||||
3.进入 `Enable application test function` 将 `Config test hash table` 选项置为 `Y`
|
||||

|
||||
4.一直选择 `Exit` 退出配置,在最后需要确认的页面选择 `Yes` 保存配置
|
||||
5.执行编译命令:`make BOARD=cortex-m3-emulator`,正常情况下应当编译无误
|
||||

|
||||
6.在 `qemu` 中运行:`qemu-system-arm -machine lm3s6965evb -nographic -kernel build/XiZi-cortex-m3-emulator.elf`
|
||||

|
||||
7.在 shell 中运行命令 `TestHash`,执行结果与预期一致,验证完成。
|
||||

|
|
@ -0,0 +1,292 @@
|
|||
/**
|
||||
* @file: test_hash.c
|
||||
* @brief: Implement a simple hash
|
||||
* @version: 1.0
|
||||
* @date: 2023/5/29
|
||||
*/
|
||||
#include <transform.h>
|
||||
#include "test_hash.h"
|
||||
|
||||
#define TABLE_SIZE 1024
|
||||
#define MAX_WORD_LEN 128
|
||||
|
||||
|
||||
/**
|
||||
* @description: element of the hash table's chain list
|
||||
* free_value is the destructor of value
|
||||
*/
|
||||
typedef struct kv
|
||||
{
|
||||
struct kv* next;
|
||||
char* key;
|
||||
void* value;
|
||||
// void(*free_value)(void*);
|
||||
}kv;
|
||||
|
||||
/* HashTable */
|
||||
typedef struct HashTable
|
||||
{
|
||||
struct kv ** table;
|
||||
}HashTable;
|
||||
|
||||
/**
|
||||
* @description: constructor of struct kv
|
||||
* @param kv - element of the hash table's chain list
|
||||
* @return void
|
||||
*/
|
||||
void init_kv(struct kv* kv)
|
||||
{
|
||||
kv->next = NULL;
|
||||
kv->key = NULL;
|
||||
kv->value = NULL;
|
||||
// kv->free_value = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: destructor of struct kv
|
||||
* @param kv - element of the hash table's chain list
|
||||
* @return void
|
||||
*/
|
||||
static void free_kv(struct kv* kv)
|
||||
{
|
||||
if (kv) {
|
||||
// if (kv->free_value) {
|
||||
// kv->free_value(kv->value);
|
||||
// }
|
||||
free(kv->key);
|
||||
// free(kv->value);
|
||||
kv->key = NULL;
|
||||
free(kv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: the classic Times33 hash function
|
||||
* @param key - hash key
|
||||
* @return unsigned int
|
||||
*/
|
||||
static unsigned int hash_33(char* key)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
while (*key) {
|
||||
hash = (hash << 5) + hash + *key++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: delete a HashTable instance
|
||||
* @param ht - HashTable*
|
||||
* @return void
|
||||
*/
|
||||
void hash_table_delete(HashTable* ht)
|
||||
{
|
||||
if (ht) {
|
||||
if (ht->table) {
|
||||
int i = 0;
|
||||
for (i = 0; i<TABLE_SIZE&&ht->table[i]!=NULL; i++) {
|
||||
struct kv* p = ht->table[i];
|
||||
struct kv* q = NULL;
|
||||
while (p) {
|
||||
q = p->next;
|
||||
free_kv(p);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
free(ht->table);
|
||||
ht->table = NULL;
|
||||
}
|
||||
free(ht);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: new a HashTable instance
|
||||
* @return HashTable*
|
||||
*/
|
||||
HashTable* hash_table_new()
|
||||
{
|
||||
HashTable* ht = malloc(sizeof(HashTable));
|
||||
if (NULL == ht) {
|
||||
hash_table_delete(ht);
|
||||
return NULL;
|
||||
}
|
||||
ht->table = malloc(sizeof(struct kv*) * TABLE_SIZE);
|
||||
if (NULL == ht->table) {
|
||||
hash_table_delete(ht);
|
||||
return NULL;
|
||||
}
|
||||
memset(ht->table, 0, sizeof(struct kv*) * TABLE_SIZE);
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: insert or update a value indexed by key
|
||||
* @param ht - radix tree root
|
||||
* @param key - new key
|
||||
* @param value - new value
|
||||
* @return int
|
||||
*/
|
||||
int hash_table_put2(HashTable* ht, char* key, void* value)
|
||||
{
|
||||
int i = hash_33(key) % TABLE_SIZE;
|
||||
struct kv* p = ht->table[i];
|
||||
struct kv* prep = p;
|
||||
|
||||
while (p) { /* if key is already stroed, update its value */
|
||||
if (strcmp(p->key, key) == 0) {
|
||||
// free(p->value);
|
||||
p->value = value;
|
||||
break;
|
||||
}
|
||||
prep = p;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (p == NULL) {/* if key has not been stored, then add it */
|
||||
char* kstr = malloc(strlen(key) + 1);
|
||||
if (kstr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
struct kv * kv = malloc(sizeof(struct kv));
|
||||
if (NULL == kv) {
|
||||
free(kstr);
|
||||
kstr = NULL;
|
||||
return -1;
|
||||
}
|
||||
init_kv(kv);
|
||||
kv->next = NULL;
|
||||
strcpy(kstr, key);
|
||||
kv->key = kstr;
|
||||
kv->value = value;
|
||||
|
||||
if (prep == NULL) {
|
||||
ht->table[i] = kv;
|
||||
}
|
||||
else {
|
||||
prep->next = kv;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: get a value indexed by key
|
||||
* @param ht - radix tree root
|
||||
* @param key - new key
|
||||
* @return void* value
|
||||
*/
|
||||
void* hash_table_get(HashTable* ht, char* key)
|
||||
{
|
||||
if(ht == NULL)return NULL;
|
||||
int i = hash_33(key) % TABLE_SIZE;
|
||||
struct kv* p = ht->table[i];
|
||||
while (p) {
|
||||
if (strcmp(key, p->key) == 0) {
|
||||
return p->value;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: remove a value indexed by key
|
||||
* @param ht - radix tree root
|
||||
* @param key - new key
|
||||
* @return void
|
||||
*/
|
||||
void hash_table_rm(HashTable* ht, char* key)
|
||||
{
|
||||
int i = hash_33(key) % TABLE_SIZE;
|
||||
|
||||
struct kv* p = ht->table[i];
|
||||
struct kv* prep = p;
|
||||
while (p) {
|
||||
if (strcmp(key, p->key) == 0) {
|
||||
free_kv(p);
|
||||
if (p == prep) {
|
||||
if(NULL==p->next)
|
||||
ht->table[i] = NULL;
|
||||
else
|
||||
ht->table[i]=p->next;
|
||||
}
|
||||
else {
|
||||
prep->next = p->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prep = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
void TestHash()
|
||||
{
|
||||
char keys[][MAX_WORD_LEN] = {
|
||||
"what",
|
||||
"where",
|
||||
"why",
|
||||
"how",
|
||||
"hello!",
|
||||
"apple",
|
||||
"12345"
|
||||
};
|
||||
int values[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
printf("\nCreate hash table and add key & value:\n");
|
||||
HashTable* ht = hash_table_new();
|
||||
if (NULL == ht) {
|
||||
printf("Create hash table failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// insert key&value into hash table
|
||||
int num = sizeof(keys) / sizeof(keys[0]);
|
||||
for (int i = 0; i < num - 1; ++i) {
|
||||
hash_table_put2(ht, keys[i], &values[i]);
|
||||
}
|
||||
|
||||
//find value by key
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)hash_table_get(ht, 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");
|
||||
hash_table_rm(ht, keys[1]);
|
||||
hash_table_rm(ht, keys[3]);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)hash_table_get(ht, 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");
|
||||
hash_table_put2(ht, keys[1], &values[1]);
|
||||
hash_table_put2(ht, keys[6], &values[6]);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)hash_table_get(ht, 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 hash table:\n");
|
||||
hash_table_delete(ht);
|
||||
ht = NULL;
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)hash_table_get(ht, 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]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PRIV_SHELL_CMD_FUNCTION(TestHash, Implement a simple hash, PRIV_SHELL_CMD_MAIN_ATTR);
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
typedef struct HashTable HashTable;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* new an instance of HashTable */
|
||||
HashTable* hash_table_new();
|
||||
|
||||
/*
|
||||
delete an instance of HashTable,
|
||||
all values are removed auotmatically.
|
||||
*/
|
||||
void hash_table_delete(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 hash_table_put2(HashTable* ht, char* key, void* value);
|
||||
|
||||
/* get a value indexed by key, return NULL if not found. */
|
||||
void* hash_table_get(HashTable* ht, char* key);
|
||||
|
||||
/* remove a value indexed by key */
|
||||
void hash_table_rm(HashTable* ht, char* key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue