2017-09-20 49 views
0

目前我在C中使用字符串作为键和值的哈希表实现。如果我想存储整数而不是字符串作为值,那么执行此操作的最佳方法是什么?我正在考虑将整数存储在字符串中,并在需要时将其转换为整数,但对于算术来说效率似乎很低。类似于在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; 
} 
+0

只是使用C++的一个选项? :| – Alexander

+7

我很困惑,为什么你不能只将键类型改为整数,并对整数键进行散列。 – Jonesinator

+0

对不起,我不清楚。我想散列一个字符串(使用char指针作为键)并存储一个整数(整数是值)。虽然我的哈希表实现使用字符串。 –

回答

1

的访问和操作与哈希表实现相关功能的假设值具有空值终止字符串的形式,他们的意义是由它们的内容(完全进行而不是,例如,由指针本身的值)。除此之外,这从new()ht_insert()函数通过strdup()复制所提供的值的事实中可以明显看出。因此,如果打算使用这些函数(而不仅仅是底层数据结构),那么存储整数的唯一选择是以某种方式将整数编码为字符串,并存储这些字符串。这就是你已经想出来的。

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

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

+0

好的,也许值得修改实现文件。什么是最有效的方法呢? –

+0

它取决于@DavidTran,你愿意做什么修改,以及你想支持哪些功能。如果您希望通过通用API支持不同类型的数据值以及特定于类型的处理,则您的条目需要附加一个记录该值类型的成员。在这种情况下,我也可以将值类型指定为联合,也许类似'union {char * as_string; int as_int;/* ... * /} val;'。然后,根据条目中携带的类型元数据,选择联盟的哪个成员访问。 –

+0

我想知道是使用那个(联合)还是将结果中的值存储为'void *',将一个结构成员添加到'hashtable_t'来跟踪它的类型,并相应地使用其他函数。这会工作吗? –