#c #generics #struct #insert #hashmap
#c #дженерики #структура #вставить #hashmap
Вопрос:
Я должен создать HashMap. Я создал две структуры. A node struct
и a table struct
. Вторая структура будет «содержать» мои узлы. Моя проблема в insert
функции: я должен вставить в свою таблицу (* t) пару (ключ, значение). Проблема в том, что тип ключа и значения должны быть универсальными. Итак, я хотел бы вставить int, double, char, ecc.. Как я могу превратить свою функцию в универсальную функцию?
insert.c
struct node{
int key;
int val;
struct node *next;
struct node *prev;
};
struct table{
int size;
struct node **list;
};
int hashCode(int key){
if(key>0)
return key-1;
return key 1;
}
void insert(struct table *t,int key,int val){
int pos = hashCode(key);
struct node *list = t->list[pos];
struct node *newNode = (struct node*)malloc(sizeof(struct node));
struct node *temp = list;
while(temp){
if(temp->key==key){
printf("%s", "Key already created");
return;
}
temp = temp->next;
}
newNode->next = list;
newNode->key = key;
newNode->val = val;
if(list!=NULL){
list->prev = newNode;
}
t->list[pos] = newNode;
newNode->prev = NULL;
}
main.c
int main(){
struct table *t = /* I create the structure */ ;
insert(t,2,3);
insert(t,3,4);
insert(t,2,3);
// insert(t,'a','c'); function insert should execute also with char, int, float, double ecc...
return 0;
}
Комментарии:
1. Вы можете использовать a
union
для хранения ключей и значений, аenum
также для указания того, какие данные хранятся.2. Я никогда не использовал union и enum, как я могу использовать их в своей функции? @jha-G
3. Вы можете создать универсальную реализацию хэша, которой предоставляется функция сравнения для ключа, и она сохраняет ключ как тип данных void (или указатель на void).
4. Параметры вставки являются Int, так как я могу передать символ, например? Мне нужно передать ей весь тип, а не только int. @PaulOgilvie
5. вы также можете использовать
void *
forkey
иvalue
и добавить дополнительный тип параметра (можно использовать enum ) в свойnode
для декодирования для исправления типа, когда это необходимо
Ответ №1:
Вы определяете объединение следующим образом :
union value {
int i;
float f;
char c;
//and so on
};
И ваш узел, подобный этому :
struct node{
int key;
union value val;
struct node *next;
struct node *prev;
};
Вы меняете аргумент своей функции следующим образом :
void insert(struct table *t, int key, union value val) {}
И вашим основным становится (я использую макрос для упрощения создания объединений) :
#define UVAL(v, k) (union value){ .k = v}
int main(){
struct table * t = NULL; //Todo
insert(t, 2, UVAL(3, i) );
insert(t, 3, UVAL(4, i));
insert(t, 2, UVAL(3, i));
return 0;
}
С некоторыми поплавками вместо :
int main(){
struct table * t = NULL; //Todo
insert(t, 2, UVAL(3.5f, f));
insert(t, 3, UVAL(4.f, f));
insert(t, 2, UVAL(3.5f, f));
return 0;
}
Комментарии:
1. Спасибо! Могу ли я спросить вас, что
{.k = v}
означает в определении?2. k представляет имя поля в объединении. Здесь я передаю i или f, поэтому после расширения макроса он станет
.i
или.f
Ответ №2:
Начиная с C11, вы можете использовать _Generic
#include <stdio.h>
#define hashCode(x) _Generic((x),
int: hash_int,
double: hash_double
)(x)
int hash_int(int value)
{
printf("Hashing %dn", value);
return 42;
}
int hash_double(double value)
{
printf("Hashing %fn", value);
return 42;
}
int main(void)
{
hashCode(3);
hashCode(3.14);
return (0);
}
Из cppreference
Объяснение
Предоставляет способ выбора одного из нескольких выражений во время компиляции на основе типа управляющего выражения
Во-первых, тип управляющего выражения подвергается преобразованиям lvalue. Преобразование выполняется только в домене типов: оно отбрасывает cvr-квалификаторы верхнего уровня и атомарность и применяет преобразования массива в указатель / функции в указатель к типу управляющего выражения, не инициируя никаких побочных эффектов или вычисляя какие-либо значения.
Тип после преобразования сравнивается с именами типов из списка ассоциаций.
Если тип совместим с именем типа одной из ассоциаций, то тип, значение и категория значения универсального выбора — это тип, значение и категория значения выражения, которое появляется после двоеточия для этого имени типа.
Если ни одно из имен типов не совместимо с типом управляющего выражения, и предоставляется ассоциация по умолчанию, то тип, значение и категория значения универсального выбора являются типом, значением и категорией значения выражения после метки default : .