【问题标题】:Qsort and Comparators weird behaviour. CQsort 和 Comparators 奇怪的行为。 C
【发布时间】:2017-08-10 09:10:53
【问题描述】:

所以,我在 C 库中的 C 程序中使用 qsort。它按预期工作,所以我决定使用比较器。

比较器 1(我用这个):

 int compare (const void * a, const void * b)
{
  if (*(double*)a > *(double*)b) return 1;
  else if (*(double*)a < *(double*)b) return -1;
  else return 0;  
}

比较器 2:

int comp (const void *a, const void *b)
{
    const double *ia = (const double *)a; // casting pointer types 
    const double *ib = (const double *)b;
    return *ia  - *ib; 
}

第一个按我的意愿工作。第二个应该和第一个一样。我想使用第二个,因为程序运行得更快一些,但它并没有真正对任何东西进行排序!

我很确定我在较小的阵列上使用了比较器 #2,并且它有效。除非我在那里遗漏了什么。

【问题讨论】:

  • 我发现很难相信这个棘手的“优化”比较器即使在被纠正为实际工作时也会明显更快,除非在最具体的情况下。请记住,qsort() 函数通过指针调用比较器。其开销可能会主导这个简单函数的性能。
  • 尝试用double diff = *ia - *ib; return *(int*)((char*)&amp;diff+4); 替换return *ia - *ib;,看看它的性能如何。这是非常特定于实现的,不完整且不推荐,但应该适用于 sizeof(int) = 4 的 little-endian。它只返回diff 的最重要的 32 位字,它应该设置符号位。还假设该字的位内容对于正差异不为零。

标签: c algorithm sorting pointers


【解决方案1】:

第二个应该和第一个一样。

乍一看应该,但仔细研究后发现它不应该。

例如,考虑比较5.34.9。很明显,第一个数字大于第二个;但是,从另一个中减去一个会产生0.4,它会在转换为int 时将向下 舍入为零,从而告诉qsort 5.34.9 彼此相等。

您想要的是将 signum 函数应用于两个参数的差异。不幸的是,C 标准没有定义一个。见this Q&A for several good work-arounds

【讨论】:

  • @Mpr.Moe 没错,你不能返回一个double 来代替int,因为qsort 是在假设你给它的函数指针的情况下编译的返回int。打破这个假设将产生未定义的行为。不过,链接问答中的技巧会奏效。
  • 我读过。无论如何都会有任何性能提升吗?我想避免比较,现在我们又回到了它。这里缺少什么?
  • @Mpr.Moe 比较并不像条件执行那么糟糕。您首先编写代码 sn-p 使用三元 ? : 运算符,它具有条件执行。比较和减法不使用条件执行,导致性能稍好。不过,所有这些都是理论,因为在实践中你几乎看不出有任何区别。
  • 天哪,我不相信他们没有正确实现这一点。实际上,signum 方式比第一个比较器稍慢(比如慢 5%)。现在,如果我在我的 OP 中使用第二个比较器,那么收益是疯狂的。从 11 秒缩短到 3 秒!太糟糕了,它不起作用。
猜你喜欢
  • 2020-01-26
  • 2011-09-01
  • 1970-01-01
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多