在C中实现多个哈希表的最佳方法?

在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;

大家好。 我目前需要在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;
    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.