所以我一直在尝试创建一个通用函数来计算某种类型的(数学)模式。 我已经将其中的一部分记下来了,但是缺少其他部分,因此它将无法编译。我需要有关如何填写那些缺失部分的帮助。
整数的众数函数使用struct count
来确定元素和频率。其定义是:
struct count {
int value; // the value of the number
unsigned int freq; // how many times the number has been seen
}
mode的整数版本输出一个数组,其中包含最频繁的数字的所有联系以及有多少联系。
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
中的对象进行排序。
答案 0 :(得分:0)
您传递给qsort
的比较函数只能 接受两个参数。
这就是您在顶部代码块中所做的。
要在第二个代码块中执行所需的操作,您需要创建cmpnum
个指针,而要创建*compare
个变量。 (例如cmpnum_type1
,cmpnum_type2
等)。这就是“干净”的方式。
另一种方法(有点混乱)是使用原始的cmpnum
,但将compare
子功能指针设置为 global :
int (*compare) (const void *, const void *);
int
cmpnum(const void *obj1, const void *obj2)
{
struct count **t1 = (struct count **) obj1;
struct count **t2 = (struct count **) obj2;
return (compare(t1->object, t2->object));
}
void
dosort(void)
{
compare = foocmp;
qsort(modelist, listsize, sizeof(struct count), cmpnum);
compare = barcmp;
qsort(modelist, listsize, sizeof(struct count), cmpnum);
}