✨ feat(lib): 添加哈希表实现及相关测试功能
🐛 fix(main): 修改OLED显示位置和配置 📝 docs(demo/list/test.c): 更新测试文件,添加哈希表测试用例main
parent
3709d3d284
commit
23116b7e3d
|
@ -1,7 +1,4 @@
|
||||||
{
|
{
|
||||||
// 使用 IntelliSense 了解相关属性。
|
|
||||||
// 悬停以查看现有属性的描述。
|
|
||||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
|
@ -10,7 +7,7 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/HW_Lib",
|
"program": "${workspaceFolder}/build/HW_Lib",
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": true,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/build",
|
"cwd": "${workspaceFolder}/build",
|
||||||
"preLaunchTask": "CMake Build",
|
"preLaunchTask": "CMake Build",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
|
|
|
@ -8,4 +8,6 @@
|
||||||
extern int Test_List(void *pVoid);
|
extern int Test_List(void *pVoid);
|
||||||
|
|
||||||
extern int Test_Queue(void *pVoid1);
|
extern int Test_Queue(void *pVoid1);
|
||||||
|
|
||||||
|
extern int Test_Hash(void* pVoid);
|
||||||
#endif //HW_LIB_T_LIST_H
|
#endif //HW_LIB_T_LIST_H
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
#include "hash_table.h"
|
||||||
|
|
||||||
typedef struct test {
|
typedef struct test {
|
||||||
int val1;
|
int val1;
|
||||||
|
@ -100,6 +101,7 @@ int Test_List(void *pVoid) {
|
||||||
// 测试销毁操作
|
// 测试销毁操作
|
||||||
printf("-----destroy----\n");
|
printf("-----destroy----\n");
|
||||||
list_destroy(&list, NULL); // 销毁链表
|
list_destroy(&list, NULL); // 销毁链表
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Test_Queue(void *pVoid) {
|
int Test_Queue(void *pVoid) {
|
||||||
|
@ -141,4 +143,16 @@ int Test_Queue(void *pVoid) {
|
||||||
printf("Pop value from front: %d\n", *popVal);
|
printf("Pop value from front: %d\n", *popVal);
|
||||||
}
|
}
|
||||||
delQueue_List(deque);
|
delQueue_List(deque);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Test_Hash(void* pVoid) {
|
||||||
|
Hash_Table_t* ht = ht_new();
|
||||||
|
ht_insert(ht, "name", "lydxh");
|
||||||
|
ht_insert(ht, "age", "18");
|
||||||
|
printf("Name:%s\nAge:%s", ht_search(ht, "name"), ht_search(ht, "age"));
|
||||||
|
ht_delete(ht, "name");
|
||||||
|
ht_delete(ht, "age");
|
||||||
|
ht_del_hash_table(ht);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ int Test_OLED(void* pVoid) {
|
||||||
OLED_Init(&oled);
|
OLED_Init(&oled);
|
||||||
OLED_CLS(&oled);
|
OLED_CLS(&oled);
|
||||||
|
|
||||||
OLED_ShowCHString(&oled, 1, 24, "星海科技机械师");
|
OLED_ShowCHString(&oled, 1, 1, "星海科技机械师");
|
||||||
|
|
||||||
OLED_DrawRect(&oled, 0, 0, 127, 63);
|
OLED_DrawRect(&oled, 0, 0, 127, 63);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
#include "hash_table.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static Hash_Item_t HT_DELETED_ITEM = {NULL, NULL};
|
||||||
|
|
||||||
|
static Hash_Item_t* ht_new_item(const char* k, const char* v) {
|
||||||
|
Hash_Item_t* i = (Hash_Item_t*)malloc(sizeof(Hash_Item_t));
|
||||||
|
i->key = strdup(k);
|
||||||
|
i->value = strdup(v);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ht_hash(const char* s, const int a, const int m) {
|
||||||
|
long hash = 0;
|
||||||
|
const int len_s = strlen(s);
|
||||||
|
for (int i = 0; i < len_s; i++) {
|
||||||
|
hash += (long)pow(a, len_s - (i+1)) * s[i];
|
||||||
|
hash = hash % m;
|
||||||
|
}
|
||||||
|
return (int)hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ht_get_hash(
|
||||||
|
const char* s, const int num_buckets, const int attempt
|
||||||
|
) {
|
||||||
|
const int hash_a = ht_hash(s, HT_PRIME_1, num_buckets);
|
||||||
|
const int hash_b = ht_hash(s, HT_PRIME_2, num_buckets);
|
||||||
|
return (hash_a + (attempt * (hash_b + 1))) % num_buckets;
|
||||||
|
}
|
||||||
|
static void ht_del_item(Hash_Item_t* i) {
|
||||||
|
free(i->key);
|
||||||
|
free(i->value);
|
||||||
|
free(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ht_del_hash_table(Hash_Table_t* ht) {
|
||||||
|
for (int i = 0; i < ht->size; i++) {
|
||||||
|
Hash_Item_t* item = ht->items[i];
|
||||||
|
if (item != NULL) {
|
||||||
|
ht_del_item(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ht->items);
|
||||||
|
free(ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_prime(const int x) {
|
||||||
|
if (x < 2) { return -1; }
|
||||||
|
if (x < 4) { return 1; }
|
||||||
|
if ((x % 2) == 0) { return 0; }
|
||||||
|
for (int i = 3; i <= floor(sqrt((double) x)); i += 2) {
|
||||||
|
if ((x % i) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int next_prime(int x) {
|
||||||
|
while (is_prime(x) != 1) {
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Hash_Table_t* ht_new_sized(const int base_size) {
|
||||||
|
Hash_Table_t* ht = (Hash_Table_t*)malloc(sizeof(Hash_Table_t));
|
||||||
|
ht->base_size = base_size;
|
||||||
|
|
||||||
|
ht->size = next_prime(ht->base_size);
|
||||||
|
|
||||||
|
ht->count = 0;
|
||||||
|
ht->items = (Hash_Item_t**) calloc((size_t)ht->size, sizeof(Hash_Item_t*));
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash_Table_t* ht_new() {
|
||||||
|
return ht_new_sized(HT_INITIAL_BASE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ht_resize(Hash_Table_t* ht, const int base_size) {
|
||||||
|
if (base_size < HT_INITIAL_BASE_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Hash_Table_t* new_ht = ht_new_sized(base_size);
|
||||||
|
for (int i = 0; i < ht->size; i++) {
|
||||||
|
Hash_Item_t* item = ht->items[i];
|
||||||
|
if (item != NULL && item != &HT_DELETED_ITEM) {
|
||||||
|
ht_insert(new_ht, item->key, item->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ht->base_size = new_ht->base_size;
|
||||||
|
ht->count = new_ht->count;
|
||||||
|
|
||||||
|
// To delete new_ht, we give it ht's size and items
|
||||||
|
const int tmp_size = ht->size;
|
||||||
|
ht->size = new_ht->size;
|
||||||
|
new_ht->size = tmp_size;
|
||||||
|
|
||||||
|
Hash_Item_t** tmp_items = ht->items;
|
||||||
|
ht->items = new_ht->items;
|
||||||
|
new_ht->items = tmp_items;
|
||||||
|
|
||||||
|
ht_del_hash_table(new_ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ht_resize_up(Hash_Table_t* ht) {
|
||||||
|
const int new_size = ht->base_size * 2;
|
||||||
|
ht_resize(ht, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ht_resize_down(Hash_Table_t* ht) {
|
||||||
|
const int new_size = ht->base_size / 2;
|
||||||
|
ht_resize(ht, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ht_insert(Hash_Table_t* ht, const char* key, const char* value) {
|
||||||
|
const int load = ht->count * 100 / ht->size;
|
||||||
|
if (load > 70) {
|
||||||
|
ht_resize_up(ht);
|
||||||
|
}
|
||||||
|
Hash_Item_t* item = ht_new_item(key, value);
|
||||||
|
int index = ht_get_hash(item->key, ht->size, 0);
|
||||||
|
Hash_Item_t* cur_item = ht->items[index];
|
||||||
|
int i = 1;
|
||||||
|
while (cur_item != NULL) {
|
||||||
|
if (cur_item != &HT_DELETED_ITEM) {
|
||||||
|
if (strcmp(cur_item->key, key) == 0) {
|
||||||
|
ht_del_item(cur_item);
|
||||||
|
ht->items[index] = item;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = ht_get_hash(item->key, ht->size, i);
|
||||||
|
cur_item = ht->items[index];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ht->items[index] = item;
|
||||||
|
ht->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ht_search(Hash_Table_t* ht, const char* key) {
|
||||||
|
int index = ht_get_hash(key, ht->size, 0);
|
||||||
|
Hash_Item_t* item = ht->items[index];
|
||||||
|
int i = 1;
|
||||||
|
while (item != NULL) {
|
||||||
|
if (item != &HT_DELETED_ITEM) {
|
||||||
|
if (strcmp(item->key, key) == 0) {
|
||||||
|
return item->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = ht_get_hash(key, ht->size, i);
|
||||||
|
item = ht->items[index];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ht_delete(Hash_Table_t* ht, const char* key) {
|
||||||
|
const int load = ht->count * 100 / ht->size;
|
||||||
|
if (load < 10) {
|
||||||
|
ht_resize_down(ht);
|
||||||
|
}
|
||||||
|
int index = ht_get_hash(key, ht->size, 0);
|
||||||
|
Hash_Item_t* item = ht->items[index];
|
||||||
|
int i = 1;
|
||||||
|
while (item != NULL) {
|
||||||
|
if (item != &HT_DELETED_ITEM) {
|
||||||
|
if (strcmp(item->key, key) == 0) {
|
||||||
|
ht_del_item(item);
|
||||||
|
ht->items[index] = &HT_DELETED_ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = ht_get_hash(key, ht->size, i);
|
||||||
|
item = ht->items[index];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ht->count--;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
#ifndef HW_LIB_HASH_TABLE_H
|
||||||
|
#define HW_LIB_HASH_TABLE_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HT_PRIME_1 151
|
||||||
|
#define HT_PRIME_2 163
|
||||||
|
#define HT_INITIAL_BASE_SIZE 53
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Hash_Item
|
||||||
|
{
|
||||||
|
char* key;
|
||||||
|
char* value;
|
||||||
|
} Hash_Item_t;
|
||||||
|
|
||||||
|
typedef struct Hash_Table
|
||||||
|
{
|
||||||
|
int base_size;
|
||||||
|
int size;
|
||||||
|
int count;
|
||||||
|
Hash_Item_t** items;
|
||||||
|
} Hash_Table_t;
|
||||||
|
|
||||||
|
Hash_Table_t* ht_new();
|
||||||
|
void ht_del_hash_table(Hash_Table_t* ht);
|
||||||
|
void ht_insert(Hash_Table_t* ht, const char* key, const char* value);
|
||||||
|
char* ht_search(Hash_Table_t* ht, const char* key);
|
||||||
|
void ht_delete(Hash_Table_t* h, const char* key);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif //HW_LIB_HASH_TABLE_H
|
5
main.c
5
main.c
|
@ -34,7 +34,7 @@ int main(int argc, char *argv[]) {
|
||||||
srand((unsigned) time(NULL));
|
srand((unsigned) time(NULL));
|
||||||
|
|
||||||
|
|
||||||
// SDL_Log("Hello, SDL3!");
|
// SDL_Log("Hello, SDL3!");
|
||||||
// int count = SDL_GetNumRenderDrivers();
|
// int count = SDL_GetNumRenderDrivers();
|
||||||
// for (int i = 0; i < count; ++i) {
|
// for (int i = 0; i < count; ++i) {
|
||||||
// const char* name = SDL_GetRenderDriver(i);
|
// const char* name = SDL_GetRenderDriver(i);
|
||||||
|
@ -160,8 +160,9 @@ int main(int argc, char *argv[]) {
|
||||||
// Test_Run("List", Test_List,NULL);
|
// Test_Run("List", Test_List,NULL);
|
||||||
// Test_RunTime("Key", Test_Key);
|
// Test_RunTime("Key", Test_Key);
|
||||||
// Test_RunTime("Queue", Test_Queue);
|
// Test_RunTime("Queue", Test_Queue);
|
||||||
|
Test_RunTime("Hash", Test_Hash);
|
||||||
// Test_RunTime("Task", Test_task);
|
// Test_RunTime("Task", Test_task);
|
||||||
Test_RunTime("OLED", Test_OLED);
|
// Test_RunTime("OLED", Test_OLED);
|
||||||
// Test_RunTime("LVGL", Test_lvgl);
|
// Test_RunTime("LVGL", Test_lvgl);
|
||||||
// Test_RunTime("TFT", Test_tft);
|
// Test_RunTime("TFT", Test_tft);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue