【问题标题】:Ordering a container on something else than the key在钥匙以外的东西上订购容器
【发布时间】:2015-10-06 10:32:38
【问题描述】:

我目前正在尝试实现 A* 算法,但遇到了一个问题:

我想保留一组不同的对象,由哈希标识(我使用过 boost::hash 和家庭,但可以使用其他任何东西)并按公共 int 值排序,这些对象的成员。

目标是能够根据 O(1) 中的 int 值检索较小的对象,并以最有效的方式保证唯一性(散列似乎是实现这一目标的好方法,但我对替代方案持开放态度)。如果满足这两个条件,我不需要遍历容器。

是否有任何已经存在的实现来回答这些规范?我的假设有误吗?我应该扩展任何现有的容器吗?

编辑:

显然不清楚“基于 int 值更小”的含义。我的意思是我的对象有一个公共属性(比如说score)。对于ab 两个对象,a < b 当且仅当a.score < b.score

我希望ab 放在一个容器中,由score 订购。如果我尝试用c.hash == a.hash 插入c,我希望插入失败。

【问题讨论】:

  • 地图或多地图怎么样?它们不是 O(1),但仍然非常快。
  • 这个int 值的域是什么?
  • @Satus :地图按键对其内容进行排序。我的键是哈希,但是我没有根据 int 值排序。
  • @ʎǝɹɟɟɟǝſ:我不明白你的问题。这是一个启发式成本,如果能回答的话。
  • 将 std::set 与自定义比较器一起使用(仅在 int 值上,或在 int 值和哈希码的对上。不清楚您是否没有重复整数值)

标签: c++ c++11 containers


【解决方案1】:

虽然std::priority_queue 是一个适配器,但它的Container 模板参数必须满足SequenceContainer,所以你不能构建一个由std::set 支持的模板。

看起来你最好的选择是同时维护一个集合和一个优先级队列,并使用前者来控制插入后者。将其封装到容器概念类中可能是个好主意,但如果您对它的使用非常本地化,您可能会使用几种方法。

【讨论】:

    【解决方案2】:

    使用自定义比较器和 std::set :

    #include <set>
    #include <string>
    
    struct Object
    {
      int value;
      long hash;
    
      std::string data;
    
      Object(int value, std::string  data) :
        value(value), data(data)
      {
    
      }
    
      bool operator<(const Object& other) const
      {
        return data < other.data;
      }
    
    };
    
    struct ObjComp1
    {
    
      bool operator()(const Object& lhs, const Object& rhs) const
      {
        return lhs.value < rhs.value;
      }
    
    };
    
    struct ObjComp2
    {
    
      bool operator()(const Object& lhs, const Object& rhs) const
      {
        if (lhs.value != rhs.value)
        {
          return lhs.value < rhs.value;
        }
    
        return lhs < rhs;
      }
    
    };
    
    int main()
    {
    
      Object o1(5, "a");
      Object o2(1, "b");
      Object o3(1, "c");
      Object o4(1, "c");
    
      std::set<Object, ObjComp1> set;
      set.insert(o1);
      set.insert(o2);
      set.insert(o3);
      set.insert(o4);
    
      std::set<Object, ObjComp2> set2;
      set2.insert(o1);
      set2.insert(o2);
      set2.insert(o3);
      set2.insert(o4);
    
        return 0;
    }
    

    第一个变体将只允许您插入 o1 和 o2,第二个变体将允许您插入 o1、o2 和 o3,因为不清楚您需要哪个。唯一的缺点是您需要为 Object 类型编写自己的 operator

    或者,如果您不想为您的数据类型创建自定义运算符 但这不那么简单

    【讨论】:

    • Obj2 似乎可以解决问题,尽管我记得尝试过它,但它并没有像我想要的那样工作......我觉得很愚蠢,但感谢您的时间。一旦我测试过你的答案,我会验证你的答案。我将只使用散列进行比较,而不是使用数据,因为我有一些更复杂的东西。再次感谢
    • 酷!请注意 2 个不同的对象可能具有相同的哈希值,所以我不知道这是否适用于 100% 的情况
    • 我相当安全,2 个数据不能具有相同的哈希值,而且我很肯定它们不能具有相同的哈希值和相同的值。用Obj2的比较器应该没问题。
    【解决方案3】:

    您可以使用 stl 类型 priority_queue。如果你的元素是整数,那么你可以这样做:

    priority_queue<int> q;
    

    优先级队列在内部使用堆实现,堆是一棵完整的二叉树,其根始终是集合的最小元素。因此,您可以通过调用 top() 在 O(1) 中进行咨询。

    但是,随着算法的进行,您需要提取带有pop() 的项目。由于是二叉树,因此提取需要 O(log N),它不是 O(1),但它是一个非常好的时间,并且与预期时间相比,它是有保证的,这将是不完美的情况哈希表 。

    我不知道在 O(1) 中维护集合和提取最小值的方法。

    【讨论】:

    • 感谢您的宝贵时间!然而,这回答了最小的方面,而不是唯一性(这就是我提到集合的原因)。根据this,priority_queue 对插入没有条件。
    • @Maravedis: 插入你使用push() 方法。
    • 投反对票的人应该解释他的理由,并表明你的身份值得和负责任。恭敬地,我声称这个观点基本上是正确的,我想知道他有什么不明白的。没有解释和匿名的反对票是没有建设性的,它无助于这类社区的精神,最终是一种懦弱的行为
    • @Irleon :push() 没有删减它。我必须在插入之前检查该元素是否已经存在于队列中,这确实效率低下。
    • @Toby 已经回答了你。您可以控制并知道维护另一个集合的插入元素;例如,您的哈希表。所以你首先测试元素是否被插入;如果为负,则插入优先级队列和哈希表;否则,你忽略它。我认为它是有效的:O(1) + O(log N) = O(log N)。无论如何,如果您的状态空间增长非常快,那么您可以考虑另一种搜索类型;以迭代加深A*为例
    猜你喜欢
    • 2018-09-24
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多