Итак, я пытался создать универсальную функцию, которая вычисляет (математический) режим некоторого типа.У меня есть часть этого, но я пропускаю другие части, поэтому он не скомпилируется.Мне нужна помощь по заполнению этих недостающих частей.
Функция режима для целых чисел использует struct count
для определения элемента и частоты.Его определение:
struct count {
int value; // the value of the number
unsigned int freq; // how many times the number has been seen
}
Целочисленная версия режима выводит массив, который содержит все связи для наиболее частого числа вместе с тем, сколько существует связей.
unsigned int mode(int* tiebuf, int* list, size_t listsize)
{
struct count modelist[listsize];
size_t modesize = 0;
// initialize modelist[]
for(int i = 0; i < listsize; i++)
{
int* found = search(list[i], modelist, modesize); // signature: search(key, list, listsize)
if(found == NULL)
{
(modelist[i]).num = &list[i];
(modelist[i]).freq = 0;
modesize++;
}
else
{
(*found).freq++;
}
}
// take the most frequent element (last in modelist)
qsort(modelist, listsize, sizeof(struct count), cmpfreq);
int mode_element = listsize-1;
// see if there are any ties for frequency
size_t tiecount = 1;
for(int i = mode_element-1; i > 0; i--)
{
if((modelist[i]).freq < (modelist[mode_element]).freq)
{
tiecount++; // overshot by 1
break;
}
}
// output the tie as an array
for(int i = 0; i < tiecount; i++)
{
tiebuf[i] = (modelist[mode_element-1-i].number);
}
return tiecount; // returns how many elements are in tiebuf
}
int cmpfreq(const void* obj1, const void* obj2)
{
struct count **t1 = (struct count**)obj1;
struct count **t2 = (struct count**)obj2;
return ( ((*t1)->freq) - ((*t2)->freq) );
}
int cmpnum(const void* obj1, const void* obj2)
{
struct count **t1 = (struct count**)obj1;
struct count **t2 = (struct count**)obj2;
return ( ((*t1)->number) - ((*t2)->number) );
}
int* tiedmode( int* list, size_t listsize, int (*cmp)(const void*, const void*) )
{
// takes the median of all ties in the mode
int ties[listsize];
int tiescount = mode(ties, list, listsize);
qsort(ties, tiescount, cmpnum); // this call doesn't work
// want to call cmpnum with cmp as an argument
// this is why we needed cmpnum
int middle = tiescount/2;
return ties[middle];
}
Теперь япланировать преобразование этого в общую запись.Первое, что нужно сделать, это изменить определение struct count
struct count {
void* object; // some object
unsigned int freq; // how many times that object has appeared
}
Сигнатура для режима также должна измениться на unsigned int mode(void* tiebuf, size_t tienum, void* list, size_t listsize, size_t objsize, int (*cmp)(const void*, const void*))
Большая проблема со вспомогательной функцией cmpnum
и вот тут у меня проблемы.Поскольку для qsort
требуется указатель функции с подписью int (*fnptr)(const void*, const void*)
, cmpnum
также требует эту подпись.Однако для сравнения объектов cmpnum
, вероятно, также необходим другой указатель функции, данный пользователем для того, чтобы сравнить их.В идеале функция cmpnum
должна выглядеть следующим образом:
int cmpnum(const void* obj1, const void* obj2, int (*compare)(const void*, const void*))
{
struct count** t1 = (struct count**)obj1;
struct count** t2 = (struct count**)obj2;
return ( compare(t1->object, t2->object) );
}
Так как бы я привел указатель функции с 3 аргументами к указателю на функцию только с 2 аргументами?Или, еще лучше, как бы я решил проблему с несоответствием между * qsort
и cmpnum
?
РЕДАКТИРОВАТЬ: Причина, по которой мне нужно cmpnum
, в первую очередь заключается виз-за tiedmode
.Эта функция берет режим и выводит медиану связей.Чтобы найти медиану, мне нужно отсортировать по номеру.Но так как это будет сделано универсально, мне нужно, чтобы пользователь сообщил библиотеке, как сортировать объект внутри struct count
.