This commit is contained in:
Your Name 2023-06-18 14:27:05 +08:00
parent 7754a149a9
commit 3f346ec8fe
6 changed files with 304 additions and 0 deletions

View File

@ -240,5 +240,9 @@ menu "test app"
bool "Config test soft timer"
default n
menuconfig USER_TEST_HASH
bool "Config test hash"
default n
endif
endmenu

View File

@ -101,5 +101,9 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),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
endif

View File

@ -0,0 +1,63 @@
# 热身赛一级赛题1基于cortex-m3-emulator实现哈希表并测试验证
## 1. 简介
基于矽璓模拟器cortex-m3-emulator实现哈希表哈希函数此采用除留余数法并采用开散列的方法使用链表结构将所有相同位置的关键码串联起来,解决冲突问题,并编写测试程序在shell终端打印结果
## 2. 数据结构设计说明
//hash结点结构
typedef struct hash_node
{
void *key; //键
void *value; //值
struct hash_node *pre; //链表前驱
struct hash_node *next; //链表后继
} hash_node_t;
// hash表结构
typedef struct hash
{
unsigned int buckets; //对应的桶的大小
hashfunc_t hash_func; //保存的hash函数的地址
hash_node_t **nodes; //二级指针,存放桶结点的首地址
}hash_t;
包括以下函数功能:
`hash_fun`: 哈希函数
`hash_alloc`:哈希表初始化
`hash_get_node_by_key`: 获取当前key值对应的桶结点的地址
`hash_lookup_entry`: 获取key值对应的value值
`hash_add_entry`: 向哈希表中添加数据
`hash_free_entry`: 释放指定key值的结点
`printhash`: 打印哈希表
`testhash`: 测试函数
## 3. 测试程序说明
测试程序提供了对哈希表的基本操作的测试,具体步骤如下:
1. 创建哈希表
2. 插入多组键值对数据
3. 将哈希表中数据打印出来
4. 查找指定键的值
5. 删除指定键的结点
6. 重新打印哈希表
在步骤二中Tom和Bob都在bucket 0中二者采用链地址头插法解决哈希冲突。
## 4. 运行结果
![](test_hash.png)
## 附录
修改/新增的文件列表:
```
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/test_hash.h
APP_Framework/Applications/app_test/test_hash/est_hash.png
```
赛题链接: https://www.gitlink.org.cn/xuos/xiuos/issues/261
提交指南: https://www.gitlink.org.cn/competitions/index/track1_2023_xiuos

View File

@ -0,0 +1,212 @@
/*
* 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: oscar1
* @date: 2023/6/18
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <transform.h>
#include "test_hash.h"
#ifdef ADD_XIZI_FETURES
//hash_func是自己定义的这里存放的是函数地址。
unsigned int hash_func(unsigned int bucket_size, void* key)
{
return (*(unsigned int*)key) % bucket_size;
}
//hash初始化并对hash_nodes所指的内存空间进行内存的初始化指针置为NULL。
hash_t *hash_alloc(unsigned int buckets, hashfunc_t hash_func)
{
hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
//assert(hash != NULL);
hash->buckets = buckets;
hash->hash_func = hash_func;
int size = buckets * sizeof(hash_node_t *);
hash->nodes = (hash_node_t **)malloc(size);
memset(hash->nodes, 0, size);
return hash;
}
//获取关键码对应的桶结点的位置通过hash函数映射之后计算出对应的bucket将对应结点的地址返回。
hash_node_t** hash_get_bucket(hash_t* hash, void* key)
{
unsigned int bucket = hash->hash_func(hash->buckets, key);
if (bucket >= hash->buckets)
{
printf("bad bucket lookup\n");
//exit(1);
}
return &(hash->nodes[bucket]);
}
//查询功能
//获取当前key值对应的桶结点的地址。
hash_node_t* hash_get_node_by_key(hash_t* hash, void* key, unsigned int key_size)
{
hash_node_t** bucket = hash_get_bucket(hash, key);
hash_node_t* node = *bucket;
if (node == NULL)
{
return NULL;
}
while (node != NULL && memcmp(node->key, key, key_size) != 0)
{
node = node->next;
}
return node;
}
//获取key值对应的value值。
void* hash_lookup_entry(hash_t* hash, void* key, unsigned int key_size)
{
hash_node_t* node = hash_get_node_by_key(hash, key, key_size);
if (node == NULL)
{
return NULL;
}
return node->value;
}
//添加结点
void hash_add_entry(hash_t* hash, void* key, unsigned int key_size, void* value, unsigned int value_size)
{
//判断表中是否已有key
if (hash_lookup_entry(hash, key, key_size))
{
//printf( "duplicate hash key\n");
return;
}
//创建结点并进行赋值
hash_node_t* node = malloc(sizeof(hash_node_t));
node->pre = NULL;
node->next = NULL;
node->key = malloc(key_size);
memcpy(node->key, key, key_size);
node->value = malloc(value_size);
memcpy(node->value, value, value_size);
//寻找结点插入位置
hash_node_t** bucket = hash_get_bucket(hash, key);
if (*bucket == NULL)
{
*bucket = node;
}
else
{
// 将新结点插入到链表头部,当前结点的后继指向下一个结点。
node->next = *bucket;
(*bucket)->pre = node;
*bucket = node;
}
}
//释放结点
void hash_free_entry(hash_t* hash, void* key, unsigned int key_size)
{
//获取结点地址
hash_node_t* node = hash_get_node_by_key(hash, key, key_size);
if (node == NULL)
{
return;
}
//释放键值空间
free(node->key);
free(node->value);
//调整指针
if (node->pre)
{
node->pre->next = node->next;
}
else
{
hash_node_t** bucket = hash_get_bucket(hash, key);
*bucket = node->next;
}
if (node->next)
node->next->pre = node->pre;
// 释放结点
free(node);
}
//打印hash表
void printhash(hash_t* hash1)
{
hash_node_t** z = hash1->nodes;
int i = 0;
for (i = 0; i < hash1->buckets; ++i)
{
if (z[i] == NULL)
continue;
printf("bucket:%d\n",i);
hash_node_t* p=z[i];
while (z[i]!= NULL)
{
printf("key:%d,value:%s\n", *(int*)(z[i]->key), (char*)(z[i]->value));
z[i] = z[i]->next;
}
z[i]=p;
}
}
//测试函数
static struct hash* count_hash;
void testhash()
{
printf("create a hash, the buckets is 10\n");
count_hash = hash_alloc(10, hash_func);
int key1=10;
char value1[]="Bob";
int key2= 20;
char value2[]="Tom";
int key3=33;
char value3[]="Cindy";
int key4=31;
char value4[]="Jerry";
int key5=42;
char value5[]="Ross";
hash_add_entry(count_hash, &key1, sizeof(key1), &value1,sizeof(value1));
hash_add_entry(count_hash, &key2, sizeof(key2), &value2, sizeof(value2));
hash_add_entry(count_hash, &key3, sizeof(key3), &value3, sizeof(value3));
hash_add_entry(count_hash, &key4, sizeof(key4), &value4, sizeof(value4));
hash_add_entry(count_hash, &key5, sizeof(key5), &value5, sizeof(value5));
printf("======================================\n");
printhash(count_hash);
printf("======================================\n");
void * query_value1=hash_lookup_entry(count_hash, &key1, sizeof(key1));
printf("Query key:%d,the answer value is %s\n",key1, (char*)query_value1);
printf("======================================\n");
printf("Delete the key: %d\n",key2);
hash_free_entry(count_hash, &key2, sizeof(key2));
printf("======================================\n");
printhash(count_hash);
printf("======================================\n");
}
PRIV_SHELL_CMD_FUNCTION(testhash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR);
#endif

View File

@ -0,0 +1,21 @@
//hash结点结构
typedef struct hash_node
{
void *key; //键
void *value; //值
struct hash_node *pre; //链表前驱
struct hash_node *next; //链表后继
} hash_node_t;
//函数指针 对应的函数名是hashfunc_t。经过typedef之后可以通过hashfunc_t来代表函数指针。
typedef unsigned int (*hashfunc_t)(unsigned int, void*);
// hash表结构
typedef struct hash
{
unsigned int buckets; //对应的桶的大小
hashfunc_t hash_func; //保存的hash函数的地址
hash_node_t **nodes; //二级指针,存放桶结点的首地址
}hash_t;

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB