【发布时间】:2019-03-27 04:35:56
【问题描述】:
所以我一直在尝试创建一个通用函数来计算某种类型的(数学)模式。 我已经把它的一部分写下来了,但缺少其他部分,所以它不会编译。我需要有关如何填写这些缺失部分的帮助。
整数的模式函数使用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 中的对象进行排序。
【问题讨论】:
-
"cmpnum 可能还需要用户提供的另一个函数指针" 您只需完全删除 cmpnum 并直接使用用户函数。
-
但是那使用一定要知道
struct count的结构。我希望struct count对用户完全隐藏。 -
抱歉没有仔细阅读代码。没有看到您正在对结构计数数组进行排序。你不需要这个。对原始数组(或其副本)进行排序,然后计算相同元素的条纹更容易。
-
等等,为什么你又需要 cmpnum 了?您正在使用 cmpnum 排序,然后立即使用 cmpfreq,这使得之前的排序完全无用。
-
啊,是的。这个问题来自我试图概括的另一个问题。我会回过头来寻找我需要
cmpnum的原因。这肯定是有原因的。
标签: c generics void-pointers