【问题标题】:std::set::insert: duplicates using a user-defined classstd::set::insert:使用用户定义的类重复
【发布时间】:2016-01-20 22:12:39
【问题描述】:

我正在使用 C++ 集容器来删除重复项,但我遇到了用户定义类的问题。我将比较运算符定义如下,效果很好:

bool operator < (const TLineSegment& other) const
{
    int cx1 = (int)((x1 + x2) / 2.0);
    int cy1 = (int)((y1 + y2) / 2.0);
    int cx2 = (int)((other.x1 + other.x2) / 2.0);
    int cy2 = (int)((other.y1 + other.y2) / 2.0);

    if (cx1 == cx2)
        return (cy1 < cy2);
    else
        return (cx1 < cx2);
}

但是,下面的代码通过添加更多的条件(在一定范围内没有重复)包含很少的重复。我发现它在大多数情况下都有效,但有时它不起作用,真的很奇怪。我发现的一种情况是两个 TLineSegments 是相同的(但不是同一个实例)并且它们都被插入了。

bool operator < (const TLineSegment& other) const
{
    const int epi = 5;
    int cx1 = (int)((x1 + x2) / 2.0);
    int cy1 = (int)((y1 + y2) / 2.0);
    int cx2 = (int)((other.x1 + other.x2) / 2.0);
    int cy2 = (int)((other.y1 + other.y2) / 2.0);

    if (abs(cx1 - cx2) < epi) {
        if (abs(cy1 - cy2) < epi) {
            return false;
        }
        else {
            return (cy1 < cy2);
        }
    }
    else {
        return (cx1 < cx2);
    }

【问题讨论】:

  • 结果相等呢?你似乎没有处理这种情况。
  • 您的逻辑有缺陷(x 轴上的所有线,其中 x1 = -n 和 x2 = +n,对于任何 n 都相同)
  • 您是有意只比较中心还是线段?两个比较器都会说中心相同的两条不同的线段相等。
  • std::set 复制对象,因为它假定

标签: c++ insert set duplicates


【解决方案1】:

让我们将线段(-n,0):(n,0) 与线段(-x,-y):(x,y) 进行比较。所以(cx1,cy1)(cx2,cy2) 都是(0,0)。对于operator&lt; 的两种实现,任一方向的结果都是false,这意味着两个线段是等价的。也就是说,任何以(0,0) 为中心的线段都等价于所有其他这样的线段?!

这显然是不正确的。

最简单的方法是利用 std::tuple 定义 operator&lt; 并执行以下操作:

std::tuple<int, int, int, int> tied() const {
    // can be just auto in C++14. typically I'd say use std::tie()
    // but we're dealing with ints right?
    return std::make_tuple(x1, y1, x2, y2);
}

bool operator < (const TLineSegment& other) const
{
    return tied() < other.tied();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多