如何使用 std::map 将 bool 映射到 3d 点结构?

Posted

技术标签:

【中文标题】如何使用 std::map 将 bool 映射到 3d 点结构?【英文标题】:How to map a bool to a 3d point struct with std::map? 【发布时间】:2011-05-24 11:05:26 【问题描述】:

如何使用以下结构:

struct point 

    int x;
    int y;
    int z;
;

作为std::map<point, bool> 的键?我应该如何为两点定义operator<

【问题讨论】:

您希望如何订购积分?还是顺序不重要? @Space_C0wb0y:它至少必须是严格的弱排序。 Operator< and strict weak ordering的可能重复 您确定不希望地图中相邻的点在此 3D 空间中彼此靠近?因为那样你就需要分形映射,实现起来要复杂得多。 +1 这个问题无论如何是因为 (a) 显然,具有很高声誉的编码人员会经常执行这个错误,即使无法理解 弱严格排序 (b) 即使我学到了一个有价值的过程中的技巧\ 【参考方案1】:

std::map 这样的标准库容器要求您的排序是“严格弱排序”,因此在设计时必须非常小心。

三元元组的典型方法如下所示:

bool operator<(const point& other) const

   if (x != other.x)
       return (x < other.x);

   if (y != other.y)
       return (y < other.y);

   return (z < other.z);

它就像一个只用于x 的比较器,但不同之处在于,如果两个xs 相同,那么您将无法比较ys。如果它们是相同的,那么您同样会陷入z 比较。

【讨论】:

Strict Weak Ordering 是矛盾的? :P @Nawaz:不; “严格”和“弱”是正交的(我认为您将“严格”与“强”混淆,或将“弱”与“放松”混淆)。 Have a read of this. 感谢您的解释和链接。 (顺便说一句,我的评论是为了娱乐。悲伤:() @Nawaz:哦,哎呀。我有时会为你的讽刺而挣扎;)【参考方案2】:

当然,boost::tuple&lt;int,int,int&gt; 会让这完全没有必要。

更新 在此处添加包罗万象的 have-your-cake-and-eat-it-it-too 无缺点解决方案。恕我直言,它摇滚!

#include <boost/tuple/tuple_comparison.hpp>

struct point 

    int x, y, z;
    point(int x, int y, int z) : x(x), y(y), z(z) 
    bool operator<(const point& rhs) const 
    
        return boost::tie(x, y, z) < boost::tie(rhs.x, rhs.y, rhs.z);
    
;

这是最重要的:一切都被优化了。编译:

int main()

    point a(1,2,3), b(3,2,1);
    bool lt = a<b;
    return lt?0:255;

使用 g++ -O2 在汇编中产生以下结果。

main:
.LFB1132:
        pushl   %ebp
        xorl    %eax, %eax
        movl    %esp, %ebp
        popl    %ebp
        ret
.LFE1132:

编译器能够有效地将整个程序优化为 ...return 0。这很整洁。


答案很简单:

struct point 

    point(int x, int y, int z) 
        : x(x), y(y), z(z) 
    int x;
    int y;
    int z;
    bool operator<(const point& rhs) const 
    
        if (x<rhs.x) return true;
        if (x==rhs.x) 
         
            if (y<rhs.y) return true;
            if (y==rhs.y) return z<rhs.z;
        
        return false;
    
;

另外,我会考虑寻找允许使用 std::lexicographical_compare 的结构的重新定义

#include <algorithm>

// ...
bool operator<(const point& rhs) const 

    return std::lexicographical_compare(&xyz, &xyz+3, &rhs.xyz, &rhs.xyz+3);

【讨论】:

通过将构造函数添加到结构 point,您使其成为非 POD。它以前是 POD。 @finnw: POD 不能有 user-defined 构造函数。见Can't C++ POD type have any constructor? @finnw, @Nawaz:关于 POD 结构的要点(删除“推荐”)。但是,我添加了一个基于来自 Boost Tuple 的 boost::tie() 的脑电波。它完全消除了竞争:) @finnw:你不应该删除评论。它对其他人有帮助。删除使讨论看起来很奇怪。 :P【参考方案3】:

一种懒惰的方法:

bool operator<( point const &pt ) const

    return ::boost::make_tuple(x,y,z) <
           ::boost::make_tuple(pt.x,pt.y,pt.z);

【讨论】:

这给了我一个绝妙的主意,我会在测试后 5 分钟内更新我的答案! tie 会不会更好更快? @Xeo,我不知道。它创建一个临时的引用结构,而不是一个临时的值结构。两者都可以被编译器优化掉。但如果不是,那么您已经引入了额外的间接层。 @Xeo:我们的想法又一次相似了,见***.com/questions/6109445/…;那是那里的一些优化壮举! (当然我需要在发布基于tie()的解决方案之前查看反汇编!)【参考方案4】:

最简单的写法是这样的:

bool operator<(const point& p) const

    if(x < p.x)
    
        return true;
    
    else if(p.x < x)
    
        return false;
    

    if( y < p.y)
    
        return true;
    
    else if( p.y < y)
    
        return false;
    

    if( z < p.z)
    
        return true;
    
    else if(p.z < z)
    
        return false;
    

    return false;


【讨论】:

没有。这不满足严格的弱排序。 @Tomalak:谢谢指点。我编辑了代码。现在正确了吗? 是的,我相信是的。比较冗长! 我的版本(两个)都更短更简单,所以我不能完全同意【参考方案5】:

如果它们应该以某种方式排序,您需要指定确切的方式(例如通过从 0/0/0 的欧几里德距离)。如果你只想区分不同的点,你可以这样做

x == x2 ? (y == y2 ?  (z < z2) : y < y2) : x < x2 

【讨论】:

没有。如果xs 不等于,您应该只使用y 的情况。如果x &gt; x2,则立即回复false【参考方案6】:

只是猜测,

bool operator<(const point& other) const

  return( memcmp( (void*) this, (void*) &other, sizeof(point)) < 0);

当然,顺序有点奇怪,因为 x,y 和 z 是有符号值,但这应该适合排序到 std::map 中,不是吗?

【讨论】:

你到底在做什么? >. 我认为你应该考虑这个解决方案。 我可以提供更多代码,但您仍然对此持怀疑态度。但由于 point 结构仅包含 3 个 int 并且是不是虚拟的,因此结构的大小是 3 int 长,(void*) 转换将 compare 方法放在第一个 int 上!比较 3 个 aligned int 的内存打印是一种比较它们与唯一性保证的方法。

以上是关于如何使用 std::map 将 bool 映射到 3d 点结构?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 将预先保留的哈希映射(std::unordered_map)与整数键和连续数据数组(std::vector)进行比较

在 COM 对象上使用 std::map?

使用shared_ptr将基类引用值复制到映射

将 JNI -> jobject(基本上是映射和/或 java 文件中的映射)转换为 std::map(c++)

std::unordered_map 如何表现? [C++]

如何合并 2 个 std::maps,并在第三个映射中输出结果