在c实现的哈希表中存储整数?

时间:2017-09-20 18:11:10

标签: c hashtable

目前我在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;
}

1 个答案:

答案 0 :(得分:1)

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

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

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