diff --git a/.vscode/launch.json b/.vscode/launch.json index c76cc72..d2c6a51 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,7 +1,4 @@ { - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { @@ -10,7 +7,7 @@ "request": "launch", "program": "${workspaceFolder}/build/HW_Lib", "args": [], - "stopAtEntry": true, + "stopAtEntry": false, "cwd": "${workspaceFolder}/build", "preLaunchTask": "CMake Build", "environment": [], diff --git a/demo/list/t_list.h b/demo/list/t_list.h index 8c9b60c..8859c00 100644 --- a/demo/list/t_list.h +++ b/demo/list/t_list.h @@ -8,4 +8,6 @@ extern int Test_List(void *pVoid); extern int Test_Queue(void *pVoid1); + +extern int Test_Hash(void* pVoid); #endif //HW_LIB_T_LIST_H diff --git a/demo/list/test.c b/demo/list/test.c index 4a38e86..2d50cbb 100644 --- a/demo/list/test.c +++ b/demo/list/test.c @@ -3,6 +3,7 @@ #include "list.h" #include "queue.h" +#include "hash_table.h" typedef struct test { int val1; @@ -100,6 +101,7 @@ int Test_List(void *pVoid) { // 测试销毁操作 printf("-----destroy----\n"); list_destroy(&list, NULL); // 销毁链表 + return 0; } int Test_Queue(void *pVoid) { @@ -141,4 +143,16 @@ int Test_Queue(void *pVoid) { printf("Pop value from front: %d\n", *popVal); } 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; } diff --git a/demo/oled/test.c b/demo/oled/test.c index 596b6a8..1f5d689 100644 --- a/demo/oled/test.c +++ b/demo/oled/test.c @@ -117,7 +117,7 @@ int Test_OLED(void* pVoid) { OLED_Init(&oled); OLED_CLS(&oled); - OLED_ShowCHString(&oled, 1, 24, "星海科技机械师"); + OLED_ShowCHString(&oled, 1, 1, "星海科技机械师"); OLED_DrawRect(&oled, 0, 0, 127, 63); diff --git a/lib/list/hash_table.cpp b/lib/list/hash_table.cpp new file mode 100644 index 0000000..cd7a57f --- /dev/null +++ b/lib/list/hash_table.cpp @@ -0,0 +1,183 @@ +#include "hash_table.h" +#include +#include +#include + +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--; +} diff --git a/lib/list/inc/hash_table.h b/lib/list/inc/hash_table.h new file mode 100644 index 0000000..433d372 --- /dev/null +++ b/lib/list/inc/hash_table.h @@ -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 diff --git a/main.c b/main.c index 2533d73..3282fac 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ int main(int argc, char *argv[]) { srand((unsigned) time(NULL)); -// SDL_Log("Hello, SDL3!"); + // SDL_Log("Hello, SDL3!"); // int count = SDL_GetNumRenderDrivers(); // for (int i = 0; i < count; ++i) { // const char* name = SDL_GetRenderDriver(i); @@ -160,8 +160,9 @@ int main(int argc, char *argv[]) { // Test_Run("List", Test_List,NULL); // Test_RunTime("Key", Test_Key); // Test_RunTime("Queue", Test_Queue); + Test_RunTime("Hash", Test_Hash); // Test_RunTime("Task", Test_task); - Test_RunTime("OLED", Test_OLED); + // Test_RunTime("OLED", Test_OLED); // Test_RunTime("LVGL", Test_lvgl); // Test_RunTime("TFT", Test_tft); return 0;