【问题标题】:Making a generic mode function in C在 C 中制作通用模式函数
【发布时间】: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 个参数的函数指针呢?或者更好的是,我将如何解决* qsortcmpnum 之间的差异问题?

编辑:我首先需要cmpnum 的原因是因为tiedmode。此函数采用模式并输出平局的中位数。为了找到中位数,我必须按数字排序。但由于这将是通用的,我需要用户让库知道如何对 struct count 中的对象进行排序。

【问题讨论】:

  • "cmpnum 可能还需要用户提供的另一个函数指针" 您只需完全删除 cmpnum 并直接使用用户函数。
  • 但是那使用一定要知道struct count的结构。我希望 struct count 对用户完全隐藏。
  • 抱歉没有仔细阅读代码。没有看到您正在对结构计数数组进行排序。你不需要这个。对原始数组(或其副本)进行排序,然后计算相同元素的条纹更容易。
  • 等等,为什么你又需要 cmpnum 了?您正在使用 cmpnum 排序,然后立即使用 cmpfreq,这使得之前的排序完全无用。
  • 啊,是的。这个问题来自我试图概括的另一个问题。我会回过头来寻找我需要cmpnum 的原因。这肯定是有原因的。

标签: c generics void-pointers


【解决方案1】:

您传递给qsort 的比较函数只能接受两个参数。

这就是您在顶部代码块中所做的。

要在第二个代码块中执行您想要的操作,您需要创建与 *compare 指针一样多的 cmpnum 变体。 (例如cmpnum_type1cmpnum_type2 等)这就是“干净”的方式。

另一种方法[有点混乱],是使用你原来的cmpnum,但让compare 子函数指针是一个全局

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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 2016-09-07
    • 2011-07-31
    • 1970-01-01
    相关资源
    最近更新 更多