qsort比较编译错误

qsort comparison compilation error

本文关键字:错误 编译 比较 qsort      更新时间:2023-10-16

My medianfilter.cpp类调用qsort,如下所示。

vector<float> medianfilter::computeMedian(vector<float> v) {
    float arr[100];
    std::copy(v.begin(), v.end(), arr);
    unsigned int i;
    qsort(arr, v.size(), sizeof(float), compare);
    for (i = 0; i < v.size(); i++) {
        printf("%f ", arr[i]);
    }
    printf("median=%d ", arr[v.size() / 2]);
    return v;
}

我比较的实施方式是:

int medianfilter::compare(const void * a, const void * b) {
    float fa = *(const float*) a;
    float fb = *(const float*) b;
    return (fa > fb) - (fa < fb);
}

而mediafilter.hpp中的声明被设置为私有,看起来像这样:

int compare (const void*, const void*);

出现编译错误:cannot convert ‘mediafilter::compare’ from type ‘int (mediafilter::)(const void*, const void*)’ to type ‘__compar_fn_t {aka int (*)(const void*, const void*)}’

我不完全理解这个错误。如何正确声明和实现此比较方法?谢谢

Compare是一个非静态成员函数,而qsort需要一个非成员函数(或静态成员函数)。由于您的compare函数似乎不使用类的任何非静态成员,因此您可以将其声明为静态。事实上,我根本不确定你的中值滤波器类是做什么的。也许您只需要一个名称空间。

为什么不直接对向量进行排序,而不是将其复制到第二个数组中?此外,如果向量包含100个以上的元素,则代码将中断。

默认的排序行为只是希望您需要,但为了完整性,我展示了如何使用比较函数。

我还更改了函数的返回类型,因为我不明白为什么一个名为computeMedian的函数不会返回中值。。

namespace medianfilter
{
    bool compare(float fa, float fb)
    {
        return fa < fb;
    }
    float computeMedian(vector<float> v)
    {
        std::sort(v.begin(), v.end(), compare);
        // or simply: std::sort(v.begin(), v.end());
        for (size_t i = 0; i < v.size(); i++) {
            printf("%f ", v[i]);
        }
        if (v.empty())
        {
            // what do you want to happen here?
        }
        else
        {
            float median = v[v.size() / 2]; // what should happen if size is odd?
            printf("median=%f ", median); // it was %d before
            return median;
        }
    }
}

不能按原样调用compare,因为它是一个成员函数,需要一个this指针(即需要在对象上调用它)。但是,由于比较函数不需要this指针,只需将其设置为static函数,代码就会编译。

在你的类中这样声明:

static int compare(const void * a, const void * b);

与您的问题没有直接关系(您已经有了答案),但有一些观察结果:

  1. 你对中位数的计算是错误的。如果元素的数量是偶数,则应返回两个中心值的平均值,而不是下一个的值
  2. 复制到具有设置大小的数组会导致缓冲区溢出。复制到另一个向量并std:对它进行排序,或者(正如@NeilKirk所建议的)只对原始向量进行排序,除非你有理由不修改它
  3. 没有防止空输入的措施。在这种情况下,中位数是未定义的,但您的实现只会返回arr[0]上发生的任何情况

好吧,这更像是Eli Algranti(优秀)答案的附录,而不是原始问题的答案。

这里有一个通用代码,用于计算称为x的二重向量的分位数quant(下面的代码保留该分位数)。

首先:分位数有很多定义(R单独列出9)。下面的代码对应于定义#5(这也是matlab中默认的分位数函数,通常是统计学家在考虑分位数时想到的函数)。

这里的关键思想是,当分位数没有落在精确的观察上时(例如,当你想要长度为10的数组的15%分位数时),下面的实现实现了相邻分位数之间的(正确的)插值(在这种情况下,在10%和20%之间)。这一点很重要,这样当你增加观察次数时(我在这里暗示medianfilter的名称),分位数的值不会突然跳跃,而是平滑收敛(这就是为什么这是统计学家首选定义的原因之一)。

代码假设x至少有一个元素(下面的代码是一个较长元素的一部分,我觉得这一点已经提出了)。

不幸的是,它是使用(优秀!)c++特征库中的许多函数编写的,在这个深夜,我翻译特征函数或清理变量名已经太晚了,但关键思想应该是可读的。

#include <Eigen/Dense>
#include <Eigen/QR>
using namespace std;
using namespace Eigen;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::VectorXi;
double quantiles(const Ref<const VectorXd>& x,const double quant){
//computes the quantile 'quant' of x.
    const int n=x.size();
    double lq,uq,fq;
    const double q1=n*(double)quant+0.5;
    const int index1=floor(q1);
    const int index2=ceil(q1);
    const double index3=(double)index2-q1;
    VectorXd x1=x;
    std::nth_element(x1.data(),x1.data()+index1-1,x1.data()+x1.size());
    lq=x1(index1-1);
    if(index1==index2){
        fq=lq;
    } else {
        uq=x1.segment(index1,x1.size()-index1-1).minCoeff();
        fq=lq*index3+uq*(1.0-index3);
    }
    return(fq);
}

因此,代码使用一个对nth_element的调用,它的平均复杂度为O(n)[对不起,使用大O表示平均值很草率],并且(当n为偶数时)在向量的最多n/2个元素上使用一个额外的对min()的调用[在本征方言中记为.minCoeff()],即O(n/2)。

这比使用部分排序(最坏情况下会花费O(nlog(n/2))或排序(会花费O(nlogn))