std::set 二维点的自定义比较器
std::set custom comparator for 2D points
我需要一个不重复的 2D 点列表,所以我使用 std::set
和自定义比较功能。我使用的函数在插入点后有问题,因为有时 std::find
找不到已经插入的点。
const double tolerance = 0.1;
struct MyPoint2D
{
MyPoint2D(double x, double y) : _x(x), _y(y) {}
double _x, _y;
};
auto compMyPoint2D = [&](const MyPoint2D& pointA, const MyPoint2D& pointB) -> bool
{
if (pointA._x < pointB._x - tolerance) return true;
if (pointA._x > pointB._x + tolerance) return false;
if (pointA._y < pointB._y - tolerance) return true;
return false;
};
std::set<MyPoint2D, decltype(compMyPoint2D)> orderedMyPoints(compMyPoint2D);
MyPoint2D pointA(0.66,1.14);
MyPoint2D pointB(0.75, 0.0);
MyPoint2D pointC(0.57,1.19);
orderedMyPoints.insert(pointA);
orderedMyPoints.insert(pointB);
orderedMyPoints.insert(pointC);
if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
{
std::cout << "Not found" << std::endl;
orderedMyPoints.insert(pointC);
if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
std::cout << "Still not found" << std::endl;
}
在插入 std::set
之前是否需要预先排序 2d 点,或者有更好的 2d 点比较功能?
我需要在插入所有点后使用std::find
来获得最终的点索引。
我在 Microsoft Visual Studio 2010 上使用本机 C++。
你的比较函数有误。取出 +-公差。这在尝试确定浮点值之间的绝对顺序时没有用。例如,它不强制等价的传递性。也就是说,如果 A == B
(即 f(A, B)
和 f(B, A)
都是假的)和 B == C
,那么 A == C
不一定是这样的那里的公差调整。
只需这样做:
if (pointA._x < pointB._x) return true;
if (pointA._x > pointB._x) return false;
if (pointA._y < pointB._y) return true;
return false;
首先,除非你有理由不这样做,否则最好只为你的 class 定义 operator<
,这意味着在使用 std::set
等时输入更少,并且意味着你可以使用中缀 <
。其次,正如本杰明指出的那样,tolerance
应该是没有必要的。第三,可以简化比较的逻辑。
你应该有这样的东西:
bool operator<(const MyPoint2D& lhs, const MyPoint2D& rhs)
{
return lhs._x < rhs._x || (lhs._x == rhs._x && lhs._y < rhs._y);
}
那你就可以用std::set<MyPoint2D>
.
我需要一个不重复的 2D 点列表,所以我使用 std::set
和自定义比较功能。我使用的函数在插入点后有问题,因为有时 std::find
找不到已经插入的点。
const double tolerance = 0.1;
struct MyPoint2D
{
MyPoint2D(double x, double y) : _x(x), _y(y) {}
double _x, _y;
};
auto compMyPoint2D = [&](const MyPoint2D& pointA, const MyPoint2D& pointB) -> bool
{
if (pointA._x < pointB._x - tolerance) return true;
if (pointA._x > pointB._x + tolerance) return false;
if (pointA._y < pointB._y - tolerance) return true;
return false;
};
std::set<MyPoint2D, decltype(compMyPoint2D)> orderedMyPoints(compMyPoint2D);
MyPoint2D pointA(0.66,1.14);
MyPoint2D pointB(0.75, 0.0);
MyPoint2D pointC(0.57,1.19);
orderedMyPoints.insert(pointA);
orderedMyPoints.insert(pointB);
orderedMyPoints.insert(pointC);
if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
{
std::cout << "Not found" << std::endl;
orderedMyPoints.insert(pointC);
if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
std::cout << "Still not found" << std::endl;
}
在插入 std::set
之前是否需要预先排序 2d 点,或者有更好的 2d 点比较功能?
我需要在插入所有点后使用std::find
来获得最终的点索引。
我在 Microsoft Visual Studio 2010 上使用本机 C++。
你的比较函数有误。取出 +-公差。这在尝试确定浮点值之间的绝对顺序时没有用。例如,它不强制等价的传递性。也就是说,如果 A == B
(即 f(A, B)
和 f(B, A)
都是假的)和 B == C
,那么 A == C
不一定是这样的那里的公差调整。
只需这样做:
if (pointA._x < pointB._x) return true;
if (pointA._x > pointB._x) return false;
if (pointA._y < pointB._y) return true;
return false;
首先,除非你有理由不这样做,否则最好只为你的 class 定义 operator<
,这意味着在使用 std::set
等时输入更少,并且意味着你可以使用中缀 <
。其次,正如本杰明指出的那样,tolerance
应该是没有必要的。第三,可以简化比较的逻辑。
你应该有这样的东西:
bool operator<(const MyPoint2D& lhs, const MyPoint2D& rhs)
{
return lhs._x < rhs._x || (lhs._x == rhs._x && lhs._y < rhs._y);
}
那你就可以用std::set<MyPoint2D>
.