使用对象作为键时保持std :: map平衡

时间:2013-04-24 16:39:15

标签: c++ binary-tree std stdmap

我正在编写一些代码,我根据设置标准存储了许多我想要回来的对象。所以对我来说,使用带有对象的地图作为关键是有意义的。对象将包含“设置标准”。

以下是我正在处理的对象类型的简化示例:

    class key
    {
         int x,y,w,h;
    }
    class object
    {
       ...
    }
    std::map<key, object, KeyCompare> m_mapOfObjects;

很简单,首先想到的是创建一个像这样的比较函数:

    struct KeyCompare
    {
       bool operator()(const key &a, const key &b)
       {
            return a.x < b.x || a.y < b.y || a.w < b.w || a.h < b.h;
       } 
    }

然后我认为这种回归的可能性非常高。所以我认为这将导致一个非常不平衡的树,因此搜索速度慢。

我主要担心的是,据我所知,std :: map以这种方式使用了这一个函数:         if(keyCompare(a,b))         {              //左边         }         否则如果(keyCompare(b,a))         {              //右边         }         其他         {               //等于         } 所以我不能只使用a.x&lt; b.x,因为那时任何具有相同x的东西都会被认为是相等的,这不是我想要的。我不介意它以这种方式排序,但它的“平等”位我似乎无法解决而不会使其失衡。

我认为将它们全部加在一起是显而易见的原因。

因此,我能想出的唯一解决方案是在信息上创建一个“UID”:

    typedef long unsigned int UIDType; 
    class key
    {           
        private:
        UIDType combine(const UIDType  a, const UIDType b) 
        {
            UIDType times = 1;
            while (times <= b)
            times *= 10;
            return (a*times) + b;
        } 

        void AddToUID(UIDType number)
        {
            if(number < m_UID)
            {
                m_UID = combine(number, m_UID);
            }
            else
            {
                m_UID = combine(m_UID, number);
            }
        }
        UIDType UID;
        public:
        int x,y,w,h;
        key()
        {
            AddToUID(x);
            AddToUID(y);
            AddToUID(w);
            AddToUID(h);
        }
    }
    struct KeyCompare
    {
       bool operator()(const key &a, const key &b)
       {
            return a.UID < b.UID;
       } 
    }

但这不仅感觉有点hacky,“long unsigned int”还不足以容纳潜在的数字。我可以把它放在一个字符串中,但速度是一个问题,我假设一个std :: string&lt;太贵了。总体而言,虽然较小的我可以使这个对象更好。

我想知道是否有人对如何做得更好有任何建议。也许我需要使用std :: map之外的其他东西,或者可能还有另一个重载。或者也许有一些明显的东西我在这里失踪了。我真的觉得我过于复杂了,也许我真的用地图咆哮着错误的树。

当我写这篇文章时,我发现分歧是获得“独特”数字的另一种方式,但也可能等于非常大的数字

2 个答案:

答案 0 :(得分:2)

您只需要实现一个strict weak ordering,您可以使用std::tie轻松实现该operator<,该#include <tuple> struct KeyCompare { bool operator()(const key& a, const key& b) const { return std::tie(a.x, a.y, a.w, a.h) < std::tie(b.x, b.y, b.w, b.h); } } 的比较std::tr1::tie执行lexicographical比较:< / p>

<tr1/tuple>

如果您没有所需的C ++ 11支持,则可以使用{{1}}中的{{1}}或来自boost库的同等版本。

答案 1 :(得分:0)

我觉得juanchopanza有一个非常好的解决方案,对于那些没有C ++ 11支持或提升库的人

我找到了一个非常简单的解决方案: What's the simplest way of defining lexicographic comparison for elements of a class?

这个解决方案适用于我的特定问题比元组更好(因为我还有一个我想考虑的值数组)。但我强烈建议将来考虑元组,我也一样。

    struct keyCompare
    {
          bool operator()(const key &a, const key&b)
          {   
            if(a.x != b.x) return a.x < b.x;
            if(a.y != b.y) return a.y < b.y;
            if(a.w != b.w) return a.w < b.w;
            if(a.h != b.h) return a.h < b.h;

            return false; //they must be equal 
          }   
    }

感谢juanchopanza的回答以及其他任何看过

的人