あなたが求めている複数のインデックスを処理する良い一般的な方法は、ペアのハッシュテーブルと、アルファキーと数値キーの順序が重要ではない可換ハッシュ関数を使用することです。
typedef struct hash_node_s {
struct hash_node_s *next;
char *keyAlpha;
unsigned keyNumeric;
void *data
} HASH_NODE, *HASH_NODE_PTR;
#define HASH_TABLE_SIZE 997
typedef HASH_NODE_PTR HASH_TABLE[HASH_TABLE_SIZE];
// Hash a string and integer in one value.
unsigned hash(char *keyAlpha, unsigned keyNumeric) {
unsigned h = 0;
for (int i = 0; keyAlpha[i]; i++) {
h = h * 31 ^ keyAlpha[i] ^ keyNumeric;
keyNumeric *= 31;
}
return h;
}
static HASH_NODE *find_or_insert(HASH_TABLE tbl, char *keyAlpha, unsigned keyNumeric) {
unsigned h = hash(keyAlpha, keyNumeric) % HASH_TABLE_SIZE;
for (HASH_NODE *p = tbl[h]; p; p = p->next)
if (strcmp(keyAlpha, p->keyAlpha) == 0 && keyNumeric == p->keyNumeric)
return p;
HASH_NODE *n = safe_malloc(sizeof *n);
n->next = tbl[h];
n->keyAlpha = safe_strdup(keyAlpha);
n->keyNumeric = keyNumeric;
n->data = NULL;
tbl[h] = n;
return n;
}
void insert(HASH_TABLE tbl, char *keyAlpha, unsigned keyNumeric, void *data) {
find_or_insert(keyAlpha, keyNumeric)->data = data;
}
void write(HASH_TABLE tbl, unsigned keyNumeric, char *keyAlpha, void *data) {
find_or_insert(keyAlpha, keyNumeric)->data = data;
}
void *read(HASH_TABLE tbl, char *keyAlpha, unsigned keyNumeric) {
return find_or_insert(keyAlpha, keyNumeric)->data;
}
void delete(HASH_TABLE tbl, char *keyAlpha, unsigned keyNumeric)
{
unsigned h = hash(keyAlpha, keyNumeric) % HASH_TABLE_SIZE;
for (HASH_NODE *q = NULL, *p = tbl[h];
p;
q = p, p = p->next)
if (strcmp(keyAlpha, p->keyAlpha) == 0 && keyNumeric == p->keyNumeric) {
if (q)
q->next = p->next;
else
tbl[h] = p->next;
safe_free(p->keyAlpha);
safe_free(p);
return;
}
}
このコードはテストされていませんが、マイナーなタイプミスを除いて信頼できるはずです。
すべての操作のコストはほぼ同じです。ハッシュ関数の計算は、キーの長さに依存します。これを除いて、すべての操作は確率的にO(1)です。つまり、ハッシュ関数が疑似ランダム結果を生成しないという悪いケースに遭遇したり、テーブルの読み込みが高くなりすぎたりしない限り、これは確かに非常に高速です。
このコードの弱点は、要素ごとに2つのキーを格納し、文字列キーが任意に大きくなる可能性があることです。ただし、これは別の文字列テーブル(文字列のハッシュテーブル)を使用して修正できるため、重複する文字列は同じポインタで表されます。文字列テーブルの挿入と削除(参照カウントがゼロに達したとき)は、safe_strdup
とのfree
呼び出しを置き換えます。他のすべての場合、コードは同じままです。これにより、ストレージのオーバーヘッドは整数とデータ項目ごとのポインタになります。