Hashmap со строковым массивом в качестве значения в C
Я строю программу на C, которая читает файл базы данных и переводит его в некоторые C-структуры.
Можно ли реализовать хеш-таблицу, которая использует int в качестве ключа и возвращает строковый массив (char **) в качестве значения (это для получения определенного кортежа в базе данных по id).
Спасибо!
2 ответа
Да, вы можете, вот пример использования SuperFastHash (комментарии в коде):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct data {
int index;
char name[16];
struct data *next;
} data;
extern char *strdup(const char *);
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]))
uint32_t SuperFastHash(const char * data, int len)
{
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += (get16bits(data));
tmp = (get16bits(data + 2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof(uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3:
hash += get16bits(data);
hash ^= hash << 16;
hash ^= ((signed char)data[sizeof(uint16_t)]) << 18;
hash += hash >> 11;
break;
case 2:
hash += get16bits(data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1:
hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
/* return data (or NULL if exists) */
data *insert(data **table, data *value, size_t n)
{
uint32_t hash;
data *temp;
char s[10];
int len;
/* convert index to string */
len = sprintf(s, "%d", value->index);
hash = SuperFastHash(s, len) % n;
if (table[hash] == NULL) {
/* not found, insert */
table[hash] = value;
} else {
temp = table[hash];
while (1) {
if (temp == value) return NULL;
if (temp->next) {
temp = temp->next;
} else break;
}
/* not found, insert */
temp->next = value;
}
return value;
}
/* return data as array of strings (or NULL if not found) */
char **search(data **table, int index, size_t n)
{
char **record;
uint32_t hash;
data *temp;
char s[10];
int len;
/* convert index to string */
len = sprintf(s, "%d", index);
hash = SuperFastHash(s, len) % n;
if (table[hash] != NULL) {
temp = table[hash];
while (temp) {
if (temp->index == index) {
/* struct to array of strings (check mallocs) */
record = malloc(sizeof(*record) * 2);
record[0] = strdup(s);
record[1] = strdup(temp->name);
return record;
}
temp = temp->next;
}
}
/* not found */
return NULL;
}
void free_record(char **record)
{
free(record[0]);
free(record[1]);
free(record);
}
int main(void)
{
data values[] = {
{4611, "Kessie", NULL},
{5141, "Neville", NULL},
{6484, "Dominic", NULL},
{2074, "Kelly", NULL},
{9969, "Petra", NULL},
{9663, "Laura", NULL},
{6136, "Bianca", NULL},
{1647, "Aurelia", NULL},
{8512, "Britanney", NULL},
{2613, "Oprah", NULL},
{2610, "Shay", NULL},
{6591, "Ralph", NULL},
{9302, "Charity", NULL},
{2593, "Lillian", NULL},
{9732, "Hop", NULL}
};
size_t i, n = sizeof(values) / sizeof(values[0]);
/* array of pointers to values */
data **table = calloc(n, sizeof(*table));
/* value as array of strings */
char **record;
if (table == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
puts("Inserting ...");
for (i = 0; i < n; i++) {
printf("%d %s\n", values[i].index, values[i].name);
insert(table, &values[i], n);
}
if (!insert(table, &values[1], n)) puts("Exists");
puts("Searching ...");
for (i = 2610; i < 2615; i++) {
record = search(table, i, n);
if (record == NULL) {
printf("%zu Not found\n", i);
} else {
printf("%s %s\n", record[0], record[1]);
free_record(record);
}
}
free(table);
return 0;
}
Но, как отметил Рикайан, сбалансированное бинарное дерево поиска - лучший вариант.
Да, это возможно. Но это действительно зависит от характера ключа. Если вы не можете найти образец того, как ключ соответствует значению, очень трудно реализовать хеш-функцию. Один из подходов заключается в реализации сбалансированного по высоте дерева двоичного поиска по ключам и сохранению значений. Это гарантировало бы наихудшую временную сложность O(logn) для каждой операции.