Как назначить несколько значений для одного и того же ключа в hashmap? - PullRequest
0 голосов
/ 11 ноября 2018

Как начинающий программист, я начал читать Язык программирования C * , чтобы узнать больше о pointers и structs.

В настоящее время я изучаю хеш-карты в C. Следуя примеру из книги, я создал свою собственную хеш-карту для хранения пар ключ-значение:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STRING_SIZE 100
#define HASHSIZE 101

static struct map *hashtab[HASHSIZE]; /* pointer table */
unsigned hash(char *);  /* hashing function: form hash value for string s. used by both lookup and install*/
char *strdup(char *);

struct map {        /* creating a map structure */
    struct map *next;
    char *KEY;          /* KEY - pointer to a char - member of nlist*/
    char *object1;      /* object - pointer to a char - member of nlist*/
};

/* lookup function takes a pointer to char - s as an argument and returns a pointer to map structure */
struct map *lookup(char *s) {
    struct map *np;

    for (np = hashtab[hash(s)]; np != NULL; np = np->next) {
        if (strcmp(s, np->KEY) == 0) {
            return np;
        }
    }
    return NULL;
}

/* install function takes a pointer to a char - KEY, object and returns a pointer to map structure */
struct map *install(char *KEY, char *object1) {
    /* install: put (name, defn) in */
    /* Install uses lookup to determine whether the KEY being installed
       is already present. Proceeds to create a new entry or update*/
    struct map *np;
    unsigned hashval;

    if ((np = lookup(KEY)) == NULL) {
        np = (struct map *) malloc(sizeof(*np));
        if (np == NULL || (np->KEY = strdup(KEY)) == NULL) {
            return NULL;
        }
        hashval = hash(KEY);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    }
    else {
        free((void *)np->object1);
    }
    if ((np->object1 = strdup(object1)) == NULL) {
        return NULL;
    }
    return np;
}

Затем я назначаю значения клавишам следующим образом:

int main(void) {

    struct map *table[4] = {
        (install("key1", "value1")),
        (install("key2", "value2")),
        (install("key3", "value3")),
        (install("key4", "value4"))
    };

    int i;

    for (i = 0; i < 4; i++) {
        printf("%s->%s\n", table[i]->KEY, table[i]->object);
    }
    printf("\n");
    return 0;
}

Код выше работает хорошо, я могу назначить value1, ..., value4 для key1, ..., key4 соответственно. Однако это не позволяет мне назначать несколько значений одному ключу.

Допустим, я прочитал следующее из текстового файла:

key1 9000 600 Test1
key2 2000 600 Test2
key3 3000 120 Test3
key4 4000 120 Test4
.
.
key10 1000 560 Test10

Я хочу иметь возможность хранить каждую клавишу и назначать ей несколько значений. Поскольку число столбцов фиксировано, возможно, я мог бы создать структуру, представляющую строку, и поместить ее в карту.

Для этого необходимо изменить install, чтобы можно было добавить несколько значений для одного и того же ключа. Поскольку ключи уникальны, lookup и uninstall (функция, которую я создал для удаления ключей) должны остаться без изменений.

Приведенный выше код работает отлично, однако я ищу общее решение для добавления нескольких значений к одним и тем же ключам.

Как мне поступить, чтобы можно было звонить:

struct map *table[4] = {
    (install("key1", "9000" ,"600", "Test1")),   //key, object1, object2, object3
    (install("key2", "2000" ,"600", "Test2")),
    (install("key3", "3000" ,"120", "Test3")),
    (install("key4", "4000" ,"120", "Test4"))
};

Другая идея была бы:

/* key points to this struct */
struct Value {
    int i;
    int k;
    char *c;
};

typedef struct map {        /* creating a map structure */
    struct map *next;
    char *KEY;
    struct Value value;  /* place multiple values inside a struct*/
};

и вот где я застреваю:

struct map *insert(char *KEY, struct *Value) {
    struct map *np;
    unsigned hashval;

    if ((np = lookup(KEY)) == NULL) {
        np = (struct map *) malloc(sizeof(*np));
        if (np == NULL || (np->KEY = strdup(KEY)) == NULL) {
            return NULL;
        }
        hashval = hash(KEY);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    }
    else {
        free((struct Value*)np->value); //type cast cannot convert from 'Value' to 'Value*'

    }
    if ((np->Value = strdup(Value)) == NULL) { //map has no field value
        return NULL;
    }

    return np;
}

Я искал следующие вопросы, но не смог извлечь соответствующую информацию о том, как реализовать это в C.

Хеш-карты, имеющие несколько ключей с несколькими значениями

Как назначить несколько значений хеш-ключу?

HashMap с многозначными ключами

Как я могу реализовать хэш-карту, которая принимает несколько значений, назначенных одной и той же клавише?


EDIT

Как указано в комментариях, структура, которую я использую, может быть не хеш-картой, а связанным списком. Однако книга специально говорит, что страница 144 - это хэш-карта.

1 Ответ

0 голосов
/ 11 ноября 2018

Возможно, это не самое лучшее решение, но благодаря приведенным выше комментариям я получил кое-что работающее. Я объявляю несколько значений в качестве указателей на char. Пожалуйста, дайте мне знать, если я могу улучшить это.

Мне еще предстоит выполнить исправление коллизий.

struct map {        /* creating a map structure */
    struct map *next;
    char *KEY;
    char *value1;
    char *value2;
    char *value3;
}; 

Затем я передаю их функции вставки.

struct map *insert(char *KEY, char *value1, char *value2, char *value3) {
    /* install: put (name, defn) in */
    /* Install uses lookup to determine whether the KEY being installed
       is already present. Proceeds to create a new entry or update*/
    struct map *np;
    unsigned hashval;

    if ((np = lookup(KEY)) == NULL) {
        np = (struct map *) malloc(sizeof(*np));
        if (np == NULL || (np->KEY = strdup(KEY)) == NULL) {
            return NULL;
        }
        hashval = hash(KEY);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    }
    else {
        free((void *)np->value1); //type cast cannot convert from 'Value' to 'Value*'
        free((void *)np->value2);
        free((void *)np->value3);
    }
    if ((np->time = strdup(value1)) == NULL) { //map has no field value
        return NULL;
    }
    if ((np->description = strdup(value2)) == NULL) { //map has no field value
        return NULL;
    }
    if ((np->duration = strdup(value3)) == NULL) { //map has no field value
        return NULL;
    }

    return np;
}

Печать их даст ключ, указывающий четыре значения.

key1->value1 value2 value3

...