【问题标题】:C++ set how to sort a set by value and search by keyC ++设置如何按值对集合进行排序并按键搜索
【发布时间】:2016-07-24 23:47:45
【问题描述】:

我正在实现A* 最短路径算法。 Openlist 部分存储将要访问的所有节点。该列表就像一个优先队列,第一个元素具有最小的成本值,因此在每次迭代中,我们只需弹出第一个元素并访问它。但是在迭代中,我们需要遍历这个节点的邻居并检查邻居是否在 Openlist 中。

也就是说这个Openlist需要支持两种操作:

  1. 自动分拣
  2. 查找节点(通过其 ID)

这里的问题是Openlist会按照cost值排序,而查找需要根据邻居节点的ID(相邻节点)。所以我正在考虑使用集合,其中元素是节点。但是我不知道如何在这个集合中通过它的 ID 来查找一个元素。

struct astar_node
{
    string id;
    double f;  //estimated cost;
    double g;  //distance from source to this node;
    double h;  //heuristic cost from this node to target;
};  

struct openlist_compare
{
    bool operator()(const astar_node &node1, const astar_node &node2 ){
           return node1.f < node2.f ;
    }
};

std::set<astar_node, openlist_compare> Openlist;

【问题讨论】:

  • 保留两套,一套由f索引,另一套由id索引。
  • 您不会在集合中通过其 ID 来查找元素 - 至少在不遍历整个集合的情况下是这样。这不是套装的用途。
  • @但是 set 的 find() 方法有什么作用呢?
  • @daydayup 给你一个指向集合中元素的迭代器?
  • @daydayup 你必须搜索它。一个集合只索引一个值。 std:: find_if(OpenList.begin(), OpenList.end(), [wantId](const astar_node&amp; node){ return node.id == wantId; }

标签: c++ set a-star


【解决方案1】:

C++ 容器,如 std::set、std::map、std::list 和 std::vector 等,是“单一用途”或“原始”容器。每个容器都有某些独特的特性,将它们与其他容器区分开来;当然,否则就没有理由首先拥有所有这些容器。

std::set 的目的是按值查找容器中的值,并在集合中仅存储唯一值,仅此而已。

std::set 与其他关联容器一样,允许您指定一个可选的比较器类,该类实际上为容器中的每个实际值指定“值”的含义。你已经做到了,实际上,定义只有 f 类的 f 成员对于定义集合包含的内容很重要。 astar_node 的所有其他成员的所有其他值都将被忽略。

一旦完成,就std::set 而言,就是这样。该集合可以通过astar_node::f 查找,仅此而已。这是在集合中找到某些东西的唯一方法。

正如我在开头所说的,std::set 和其他容器是“原始”容器,有时您需要一些更复杂的东西,就像这里的情况一样。在这种情况下,您可以使用多个容器,并以某种方式将它们组合起来以达到预期的效果。没有法律禁止使用多个容器来存储一组数据。没有法律规定您必须使用单个容器来执行您需要执行的所有操作,以及特定的数据集合。

这里,据我了解,您还需要能够在id 值的集合中找到astar_node。

很好:

typedef std::set<astar_node, openlist_compare> openlist_t;

openlist_t Openlist;

std::map<std::string, openlist_t::iterator> OpenList_by_id;

在您将insert() 一个新的astar_node 放入您的OpenList 之后,insert() 会为openlist_t 中的新元素返回一个迭代器。您将获得插入的astar_node 的迭代器。取这个迭代器,放入OpenList_by_id,键为id。

现在,当您想在给定 id 的情况下在 OpenList 中查找某些内容时,请使用映射查找迭代器,然后取消引用它。问题解决了。

另外:

  1. remove() 从std::set 中提取astar_node 还需要从OpenList_by_id 查找映射中删除其迭代器。

  2. 由于std::set包含唯一值,您需要处理集合中已存在具有相同f的astar_node的情况,并适当处理此情况。

    李>

【讨论】:

  • 谢谢您,先生!你这个人。谢谢楼上各位提供帮助。对于 2,答案是使用多重集吗?谢谢。
  • 是的,如果您确实希望支持多个值,std::multiset 将是最简单的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 2017-05-02
  • 2015-10-18
  • 2021-12-20
相关资源
最近更新 更多