2017-09-20 3 views
0

現在、キーと値として文字列を使用するCでのハッシュテーブルの実装があります。値として文字列の代わりに整数を格納したい場合は、これを行うにはどうすればよいでしょうか?私は整数を文字列に格納し、それを必要に応じて整数に変換することを考えていますが、算術演算には非効率的です。何かのように整数をc実装のハッシュテーブルに格納していますか?

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

もっと良い方法がありますか?

EDIT:あなたのハッシュテーブルの実装に関連付けられたハッシュテーブルの実装

#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

アクセスおよび操作機能は、(値がnullで終わる文字列の形式を持っていると仮定し、その重要性は、その内容によって完全に運ばれていること例えば、ポインタそのものの値ではない)。とりわけ、これは、new()ht_insert()関数がstrdup()で指定された値のコピーを作成していることから明らかです。したがって、これらの関数(基本的なデータ構造だけでなく)を使用する場合、整数を格納する唯一の方法は、整数を何らかの方法で文字列にエンコードし、その文字列を格納することです。これはあなたがすでに思いついたものです。

これは、文字列と整数の両方を同じハッシュテーブルに格納できるようにする場合には、少し問題があることに注意してください。テーブルエントリはデータ型のメタデータを記録する方法を提供しないので、文字列と数値表現の衝突を避けるために、データ型を格納する値にエンコードする必要があります。整数だけでなく文字列も。たとえば、最初の文字がデータ型を伝達する文字列に値をエンコードすることができます。したがって、おそらく"S12345"文字列"12345"を表し、"I12345"整数12345を表します。しかし、すべての値がテーブルごとに統一されたタイプであると仮定すると、そのようなトリックは必要ありません。

既存のデータ構造に整数を格納するための代替ハッシュテーブル関数の少なくとも一部を書くことができれば、より多くの選択肢があります。たとえば、ポインターと整数を前後に(インプリメンテーション定義の結果を使用して)変換できるという事実を使用することができます。しかし、代替機能を使用することは、実装を変更することと事実上同じですから、あなたはそのようなアプローチを拒否したと解釈します。

+0

さて、実装ファイルを変更する価値があるかもしれません。それを行う最も効果的な方法は何ですか? –

+0

これは、@DavidTran、どのような変更を加えようとしているのか、サポートしたい機能に依存します。タイプ固有の処理を使用して、汎用APIを使用してさまざまなタイプのデータ値をサポートしたい場合は、値のタイプが記録される追加メンバーを入力する必要があります。その場合、値の型を共用体として指定することもできます。多分 'union {char * as_string; int as_int;/* ... * /} val; '次に、エントリによって運ばれるタイプ・メタデータに基づいて、どのユニオン・メンバーをアクセスするかを選択します。 –

+0

私はその(共用体)を使用するか、構造体の値を 'void *'として格納するか、構造体メンバを 'hashtable_t'に追加してその型を追跡し、それに応じて他の関数で動作するのか疑問に思っていました。これはうまくいくのでしょうか? –

関連する問題