【C++】关于cmp函数的一点细节

【今日刷算法题遇到一个测试点总是段错误,把所有可能的地方都修了一遍发现是cmp加了取等的问题,遂记录之:】

在排序时,如果将比较函数写成
bool cmp(Node n1, Node n2) { if (n1.x==n2.x) return n1.y>=n2.y; return n1.x>n2.x; }

可能会导致段错误(segmentation fault)。其原因主要与排序算法的要求有关。

标准库中的排序算法( std::sort)要求比较函数满足 严格弱序(strict weak ordering)条件。严格弱序要求满足以下几个条件:

  1. 非自反性(Irreflexivity):对于任何元素 acomp(a, a) 返回 false
  2. 反对称性(Antisymmetry):对于任何元素 ab,如果 cmp(a, b)true,则 cmp(b, a) 必须为 false
  3. 传递性(Transitivity):对于任何元素 abc,如果 cmp(a, b)true,且 cmp(b, c)true,则 cmp(a, c) 也必须为 true

比较函数:

bool cmp(Node n1, Node n2) {
    if (n1.x == n2.x) return n1.y > n2.y;
    return n1.x > n2.x;
}

满足严格弱序,因为它明确区分了 n1.yn2.y 的比较。

而比较函数:

bool cmp(Node n1, Node n2) {
    if (n1.x == n2.x) return n1.y >= n2.y;
    return n1.x > n2.x;
}

则不满足严格弱序。具体来看,如果 n1n2x 值相等且 n1.y 等于 n2.y,此时 n1.y >= n2.y 返回 true,而 n2.y >= n1.y 也会返回 true,这会违反反对称性(Antisymmetry),导致排序算法无法正常工作,从而引发段错误。

如果两个 Node 对象的 xy 值都相同,那么从严格意义上讲,它们是不可区分的。在这种情况下,排序函数的行为确实应该表明这些对象是相等的,以满足严格弱序的要求。 如果不需要进一步区分它们,那么可以保持原来的比较函数:

bool cmp(Node n1, Node n2) {
    if (n1.x == n2.x) return n1.y > n2.y;
    return n1.x > n2.x;
}

这种情况下,排序算法会将 xy 都相同的节点视为相等,不会违反严格弱序的要求。

总结起来,确保排序函数符合严格弱序是关键。如果两个节点在所有比较字段上都相同,并且你没有其他字段来区分它们,排序函数需要明确地处理这些情况,以避免段错误和未定义行为。

posted @ 2024-07-13 13:11  Unalome  阅读(9)  评论(0编辑  收藏  举报  来源