demo
This commit is contained in:
parent
7754a149a9
commit
3f346ec8fe
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. 运行结果
|
||||

|
||||
|
||||
## 附录
|
||||
|
||||
修改/新增的文件列表:
|
||||
```
|
||||
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
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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 |
Loading…
Reference in New Issue