std::map唯一 std::less<> 2D 点作为键的功能

std::map unique std::less<> function for a 2D point as key

本文关键字:std 功能 2D 唯一 lt map gt less      更新时间:2023-10-16

嗯,经过四个小时的调试,尽管我很困惑,但我找到了问题的原因…

我正在制作一些程序,在std::map中保存一些点,并在我的窗口中渲染这些点。但奇怪的是,有些点没有出现在地图上。

std::map<Point2, Prop*> m_Props_m;
void AddProp(std::pair<Point2, Prop*> p)
{
    m_Props_m.insert(p);
}
struct Point2
{
unsigned int Point2::x;
unsigned int Point2::y;
//--------
Point2::Point2()
    :x(0)
    ,y(0)
{}
bool Point2::operator< (const Point2& b) const
{
    return ( x+y < b.x+b.y );
}
bool Point2::operator> (const Point2& b) const
{
    return ( x+y > b.x+b.y );
}
};

感谢上帝,我有一些二叉树的经验,所以我可以找到我的问题的原因。

假设我们有2个Point2。

Point2 a(0,1);
Point2 b(1,0);

可以看到,使用操作符<方法将返回false,操作符>也将返回false。因此,如果a已经在映射中,而插入b,则插入失败。

现在,这一切都很好,但我怎么能解决这个问题?有没有一种方法可以让二维点的小于算子允许我存储地图上的每个唯一点?

std::map根本不使用operator>,所以您不必担心。

要对多个字段(在本例中为两个)进行排序,请使用所谓的"字典排序",这意味着第一个字段最重要,第二个字段打破联系:

bool operator<(const Point2 &lhs, const Point2 &rhs) {
    return (lhs.x < rhs.x) || ((lhs.x == rhs.x) && (lhs.y < rhs.y));
}

如果点的坐标之和相等,则比较函数认为点相等。例如,(2,5)等价于(3,4),因为2 + 5 = 3 + 4。在地图中已经有对应点的点不会出现

一个更好的办法是先比较x,如果两个点的x值相等,再比较y。

bool operator< (const Point2 &lhs, const Point2 &rhs) {
    return (lhs.x < rhs.x) || ((lhs.x == rhs.x) && (lhs.y < rhs.y));
}

这应该能奏效:

bool Point2::operator< (const Point2& b) const
{
    if (x<b.x) return true;
    else if (!(b.x<x) && y<b.y) return true;
    else return false;
}

std::map只使用operator<。如果!(a<b) && !(b<a), ab是相等的(不等于等于),那么映射将只存储它们中的一个。未使用operator>

在其他情况下比较Point2可能没有意义,因此为了避免误解,我建议您为映射提供比较函数,并从类中删除operator<

bool mapLessPoint2(const Point2& a, const Point2& b);
std::map<Point2, Prop*, &mapLessPoint2> m_Props_m;

在我看来,操作符重载应该只在对给定类型有意义的情况下使用,并且2D空间中的一个点比2D空间中的另一个点大是不直观的。