在C中实现多个哈希表的最佳方法?
大家好。 我目前需要在C中实现3种不同的哈希表。 我试图想出一个主意,如何在不编码“创建”、“设置”、“获取”的情况下初始化这些。。等功能,我需要的每一个表 这些桌子看起来像在C中实现多个哈希表的最佳方法?,c,hashtable,C,Hashtable,大家好。 我目前需要在C中实现3种不同的哈希表。 我试图想出一个主意,如何在不编码“创建”、“设置”、“获取”的情况下初始化这些。。等功能,我需要的每一个表 这些桌子看起来像 typedef struct ht_can_t { uint32_t key; list_variable *variables; struct ht_can_t *next; } ht_can_t; typedef struct ht_iena_t { uint32_t key;
typedef struct ht_can_t {
uint32_t key;
list_variable *variables;
struct ht_can_t *next;
} ht_can_t;
typedef struct ht_iena_t {
uint32_t key;
list_variable *variables;
struct ht_iena_t *next;
} ht_iena_t;
typedef struct ht_variable_t {
char *key;
uint8_t length;
uint8_t *data;
struct ht_variable_t *next;
} ht_variable_t;
typedef struct {
ht_can_t **entry;
} ht_can;
typedef struct {
ht_iena_t **entry;
} ht_iena;
typedef struct {
ht_variable_t **entry;
} ht_variable;
我只会在初始化期间编写这些表一次,然后在运行时读取信息
我当时创建、写入、添加到这个表中的所有函数都会解决这个问题,因此下面只是CAN部分
ht_can *ht_create_can(void) {
// Alloc space for entry
ht_can *ht = malloc(sizeof(ht_can));
// Alloc space for TABLE_SIZE times CAN Hashtable
ht->entry = malloc(sizeof(ht_can_t*) * TABLE_SIZE);
// Write NULL to every entry
for (int i=0; i < TABLE_SIZE; ++i) {
ht->entry[i] = NULL;
}
return ht;
}
ht_can_t *ht_add_can(uint32_t key, list_variable* var) {
// Alloc space for Hashtable
ht_can_t *entry = malloc(sizeof(ht_can_t));
// Write Key
entry->key = key;
// Write variable list
entry->variables = var;
// Write next as NULL
entry->next = NULL;
return entry;
}
void ht_set_can(ht_can *ht, uint32_t key, list_variable* var) {
// Get Hash value
int slot = hash_int(key);
// Access entry with Hash
ht_can_t *entry = ht->entry[slot];
// Write to if empty
if (entry == NULL) {
ht->entry[slot] = ht_add_can(key, var);
return;
}
// Search for machtching Key
while (entry != NULL) {
if (entry->key == key) {
entry->variables = var;
return;
}
entry = entry->next;
}
// if no matching key found, add to end of hashtable
entry->next = ht_add_can(key, var);
}
list_variable* ht_get_can(ht_can *ht, uint32_t key) {
// Get Hash value
int slot = hash_int(key);
// Access entry with Hash
ht_can_t *entry = ht->entry[slot];
// Return if not exist
if (entry == NULL) {
return NULL;
}
// Search for matching key
while (entry != NULL) {
if (entry->key == key) {
// Return variable List
return entry->variables;
}
entry = entry->next;
}
// Return if no matching Key exist
return NULL;
}
ht\u can*ht\u create\u can(无效){
//允许进入的空间
ht_-can*ht=malloc(尺寸(ht_-can));
//表\u大小时间的Alloc空间可用于哈希表
ht->entry=malloc(sizeof(ht\U can\U t*)*表格大小);
//将NULL写入每个条目
对于(int i=0;i<表大小;++i){
ht->entry[i]=NULL;
}
返回ht;
}
ht_can_t*ht_add_can(uint32_t键,列表变量*var){
//哈希表的Alloc空间
ht_can_t*entry=malloc(sizeof(ht_can_t));
//写密钥
输入->键=键;
//写变量列表
条目->变量=var;
//将下一个写为空
entry->next=NULL;
返回条目;
}
无效ht\U设置\U can(ht\U can*ht,uint32\U t键,列表变量*var){
//获取哈希值
int slot=hash_int(键);
//使用散列访问条目
ht_can_t*entry=ht->entry[slot];
//如果为空,则写入
if(条目==NULL){
ht->entry[slot]=ht\U add\U can(键,变量);
返回;
}
//搜索马赫键
while(条目!=NULL){
如果(输入->键==键){
条目->变量=var;
返回;
}
进入=进入->下一步;
}
//若并没有找到匹配的键,则添加到哈希表的末尾
输入->下一步=ht\U添加\U can(键,变量);
}
列表变量*ht\U get\U can(ht\U can*ht,uint32\U t键){
//获取哈希值
int slot=hash_int(键);
//使用散列访问条目
ht_can_t*entry=ht->entry[slot];
//如果不存在,则返回
if(条目==NULL){
返回NULL;
}
//搜索匹配的密钥
while(条目!=NULL){
如果(输入->键==键){
//返回变量列表
返回条目->变量;
}
进入=进入->下一步;
}
//如果不存在匹配的密钥,则返回
返回NULL;
}
我需要每隔一张表再写一次吗?
还是有不同的方式
我试图想出一个主意,如何在不编码“创建”、“设置”、“获取”的情况下初始化这些。。等功能,我需要的每一个表
在C中实现模板的方法基本上是有限的
- 使用单个大型宏。不要重新发明轮子-对于通常可用的列表,newlib也有它。如果不是,它只是一个要复制的标题。我还记得看到了一个哈希表的头——当然gihtub上有很多实现
卡米尔库克给出了一个很好的回答。但是,如果您发现预处理器令人望而生畏,另一种方法是使用您喜欢的任何脚本语言,只需编写一个生成源文件的脚本
缺点是它会使构建过程复杂化,但好处是Python和类似语言比C宏更容易阅读。在我看来,您应该在结构中存储维护表所需的元素。您需要一个比较函数来比较两个条目是否相等,以便能够检测冲突,您需要一个计算键的哈希值的函数,以及一个分配项的键(和/或数据元素)副本(如果需要)的函数,以防只存储引用或对象的完整副本。在构造哈希表时,应该向这些函数传递指针,并且应该在内部使用它们来管理条目。然后,只需一个实现,就可以处理所有这些哈希表。听起来最好是使用C++的软件,但这可能会破坏我2个月XD的工作。我正在用SW4STM32开发STM32H7。不幸的是,这已经针对C进行了优化,我会在其他地方遇到更多问题。^^'如果你能找到解决方案,我很确定这不会让事情变得更容易。:)Thx:D这是我可以使用的一些输入!这可能会给我一段时间的安全(在未来的项目中也会考虑)
#define DECL_HASH(N, T) \
\
typedef struct {\
ht_##N##_t **entry;\
} ht_##N;\
\
typedef struct ht_##N##_t { \
uint32_t key; \
T *variables; \
struct ht_##N##_t *next; \
} ht##N##_t; \
\
ht_##N *ht_create_##N(void) { \
ht_##N *ht = malloc(sizeof(*ht)); \
ht->entry = malloc(sizeof(ht##N##_t*) * TABLE_SIZE); \
for (int i=0; i < TABLE_SIZE; ++i) { \
ht->entry[i] = NULL; \
} \
return ht; \
} \
\
/* etc. for each function to do */
DECL_HASH(can, list_variables)
struct iena_data_s { list_variables variables; };
DECL_HASH(iena, struct iena_data_s)
//etc.
// hash.t.h
// handy macros for concatenation
#define _c_(a, b) a##b
#define _c(a, b) _c_(a, b)
#define _c3_(a, b, c) a##b##c
#define _c3(a, b, c) _c3_(a, b, c)
// use preprocssor so that you do not have to type ( ) so much
#define ht_name_t _c3(ht_, NAME, _t)
#define ht_name _c(ht_, NAME)
typedef struct {
ht_name_t **entry;
} ht_name;
typedef struct ht_name_t { \
uint32_t key;
TYPE *variables;
struct ht_name_t *next;
} ht_name_t;
#define ht_create_name _c(ht_create_, NAME)
ht_name *ht_create_name(void) {
ht_name *ht = malloc(sizeof(*ht));
ht->entry = malloc(sizeof(ht##N##_t*) * TABLE_SIZE);
for (int i=0; i < TABLE_SIZE; ++i) {
ht->entry[i] = NULL;
}
return ht;
}
#define ht_add_name _c(ht_add_, NAME)
ht_name_t *ht_add_name(uint32_t key, list_variable* var) {
...
}
/* etc. for each function */
// pick up the trash
#undef ht_add_name
#undef ht_create_name
#undef ht_name
#undef ht_name_t
#undef _c3
#undef _c3_
#undef _c_
#undef _c
#undef NAME
// hash_can.c
#define NAME can
struct can_type_s { list_variables *variables; };
#define TYPE struct can_type_s
#include "hash.t.h"
// hash_iena.c
#define NAME iena
struct can_iena_s { list_variables *variables; };
#define TYPE struct can_iena_s
#include "hash.t.h"
// hash.c
typedef void *hash_elem;
struct hash_elem_vtable_s {
// add all functions that you will need, no idea which
int (*init)(hash_elem**); // constructor
int (*copy)(hash_elem* to, const hash_elem*from); // assignemnt
int (*move)(hash_elem** to, const hash_elem*from); // move constructor
int (*destroy)(hash_elem*); // destructor
};
struct hash_s {
void *elem;
const struct hash_elem_vtable_s *ev;
struct hash_s *next;
};
int hash_add(hash_s *t, hash_elem *elem_to_add) {
...
int r = t->ev->move(&t->elem, elem_to_add);
if (!r) return -ERROR_NUMBER;
...
}
// then instantiate hash_s for each element type.