【问题标题】:Storing integers in c-implemented hash tables?在 c 实现的哈希表中存储整数?
【发布时间】:2018-03-01 22:15:17
【问题描述】:

目前我在 C 语言中有一个哈希表实现,它使用字符串作为键和值。如果我想存储整数而不是字符串作为值,那么最好的方法是什么?我正在考虑将整数存储在字符串中,并在需要时将其转换为整数,但这对于算术来说似乎效率低下。类似的东西

insert("money", "13");
int i = atoi(get("key1"));
int sum = i + 10;
insert("money", itoa(sum));

有没有更好的方法来做到这一点?

编辑:哈希表实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct tableentry /* hashtab entry */
{
    struct tableentry *next;
    char *key;
    char *val;
} tableentry_t;

typedef struct hashtable
{
    size_t size;
    struct tableentry **tab;
} hashtable_t;

/* creates hashtable */
/* NOTE: dynamically allocated, remember to ht_free() */
hashtable_t *ht_create(size_t size)
{
    hashtable_t *ht = NULL;
    if ((ht = malloc(sizeof(hashtable_t))) == NULL)
        return NULL;
    /* allocate ht's table */
    if ((ht->tab = malloc(sizeof(tableentry_t) * size)) == NULL)
        return NULL;
    /* null-initialize table */
    int i;
    for (i = 0; i < size; i++)
        ht->tab[i] = NULL;
    ht->size = size;
    return ht;
}

/* creates hash for a hashtab */
static unsigned hash(hashtable_t *ht, char *s)
{
    unsigned hashval;
    for (hashval = 0; *s != '\0'; s++)
        hashval = *s + 31 * hashval;
    return hashval;
}

/* loops through linked list freeing */
static void te_free(tableentry_t *te)
{
    tableentry_t *next;
    while (te != NULL)
    {
        next = te->next;
        free(te->key);
        free(te->val);
        free(te);
        te = next;
    }
}

/* creates a key-val pair */
static tableentry_t *new(char *k, char *v)
{
    tableentry_t *te = NULL;

    if ((te = calloc(1, sizeof(*te))) == NULL
        || (te->key = strdup(k)) == NULL
        || (te->val = strdup(v)) == NULL)
    {
        te_free(te);
        return NULL;
    }
    te->next = NULL;
    return te;
}

static tableentry_t *lookup(hashtable_t *ht, char *k)
{
    tableentry_t *te;
    /* step through linked list */
    for (te = ht->tab[hash(ht, k) % ht->size]; te != NULL; te = te->next)
        if (strcmp(te->key, k) == 0)
            return te; /* found */
    return NULL; /* not found */
}

/* inserts the key-val pair */
hashtable_t *ht_insert(hashtable_t *ht, char *k, char *v)
{
    tableentry_t *te;
    /* unique entry */
    if ((te = lookup(ht, k)) == NULL)
    {
        te = new(k, v);
        unsigned hashval = hash(ht, k) % ht->size;
        /* insert at beginning of linked list */
        te->next = ht->tab[hashval]; 
        ht->tab[hashval] = te;
    }
    /* replace val of previous entry */
    else
    {
        free(te->val);
        if ((te->val = strdup(v)) == NULL)
            return NULL;
    }
    return ht;
}

/* retrieve value from key */
char *ht_get(hashtable_t *ht, char *k)
{
    tableentry_t *te;
    if ((te = lookup(ht, k)) == NULL)
        return NULL;
    return te->val;
}

/* frees hashtable created from ht_create() */
void ht_free(hashtable_t *ht)
{
    int i;
    for (i = 0; i < ht->size; i++)
        if (ht->tab[i] != NULL)
            te_free(ht->tab[i]);
    free(ht);
}

/* resizes hashtable, returns new hashtable and frees old*/
hashtable_t *ht_resize(hashtable_t *oht, size_t size)
{
    hashtable_t *nht; /* new hashtable */
    nht = ht_create(size);
    /* rehash */
    int i;
    tableentry_t *te;
    /* loop through hashtable */
    for (i = 0; i < oht->size; i++)
        /* loop through linked list */
        for (te = oht->tab[i]; te != NULL; te = te->next)
            if (ht_insert(nht, te->key, te->val) == NULL)
                return NULL;
    ht_free(oht);
    return nht;
}

【问题讨论】:

  • 只是使用 C++ 的一个选项吗? :|
  • 我很困惑为什么不能将键类型更改为整数,然后对整数键进行哈希处理。
  • 对不起,我不清楚。我想用一个字符串散列(使用 char 指针作为键)并存储一个整数(整数是值)。不过,我的哈希表实现对两者都使用了字符串。
  • "我的哈希表实现使用字符串" --> 发布该代码,否则这太宽泛了。
  • 如果它必须是“未修改的”,那么你可以做你现在正在做的事情,将数字转换为字符串。这将是低效的,并且会消耗更多的内存。

标签: c hashtable


【解决方案1】:

与您的哈希表实现相关的访问和操作函数假定值具有以 null 结尾的字符串的形式,并且它们的重要性完全由它们的内容来承载(例如,不是由指针本身的值) .除其他外,这从new()ht_insert() 函数通过strdup() 复制提供的值这一事实中可以明显看出。因此,如果您打算使用这些函数(而不仅仅是底层数据结构),那么存储整数的唯一选择是以某种方式将整数编码为字符串,然后存储字符串。这是你已经想到的。

请注意,顺便说一下,如果您希望能够将字符串和整数存储在同一个哈希表中,这会带来一些问题。表条目不提供任何记录数据类型元数据的方法,因此为了避免字符串和数字表示之间的冲突,您需要将数据类型编码到您存储的值中——不仅对于整数,对于字符串也是如此.例如,您可以将值编码为字符串,其第一个字符传达数据类型。因此,"S12345" 可能代表 字符串 "12345",而"I12345" 代表 整数 12345。但是,如果您假设所有值都是统一类型的,那么您就不需要这些技巧了。

如果您愿意编写至少部分替代哈希表函数以在现有数据结构中存储整数,您将有更多选择。例如,您可能会使用指针和整数可以来回转换(使用实现定义的结果)这一事实。但我认为你拒绝了这种方法,因为使用替代函数实际上与修改实现是一回事。

【讨论】:

  • 好的,也许修改实现文件是值得的。最有效的方法是什么?
  • 这取决于@DavidTran,您愿意进行哪些修改,以及您希望支持哪些功能。如果您想通过通用 API 支持不同类型的数据值,并使用特定于类型的处理,那么您的条目需要带有一个用于记录值类型的附加成员。在这种情况下,我还可以将值类型指定为联合,可能类似于union { char *as_string; int as_int; /* ... */ } val;。然后可以根据条目携带的类型元数据来选择要访问联合的哪个成员。
  • 我想知道是使用那个(联合)还是将结构中的值存储为void *,将结构成员添加到hashtable_t 以跟踪它的类型,并采取相应措施与其他功能。这也行吗?
  • 这是两个不同的问题。首先,是的,如果每个哈希表要携带一致类型的值,那么您可以将传达该数据类型的元数据一次性放入整体哈希表类型中,而不是放入每个条目中。其次,是的,您可以在各种情况下使用void *, +/- 实际动态分配来存储值。请注意,需要动态内存分配的方法比不需要的方法成本更高。
猜你喜欢
  • 2012-05-27
  • 2017-03-20
  • 2011-02-27
  • 2011-01-30
  • 2012-03-15
  • 2016-03-25
  • 2017-01-22
  • 1970-01-01
相关资源
最近更新 更多