【问题标题】:STL heap containing pointers to objects包含指向对象的指针的 STL 堆
【发布时间】:2013-03-14 20:56:09
【问题描述】:

我有一个std::list<MyObject*> objectList 容器,我需要在以下场景中对其进行排序和维护:

  • 每个对象都有一个提供成本(例如浮点值)的特定字段。该成本值用于比较两个对象,就好像它们是浮点数一样
  • 集合必须是有序的(升序),并且必须快速找到新插入元素的正确位置。
  • 可以删除最低元素(就成本而言),也可以更新几个任意定位元素的成本。然后列表必须尽快重新排序,利用其已经排序的特性。

我可以使用任何其他 stl 容器/机制来允许三个行为属性吗?它非常类似于堆,我认为使用make_heap 可能是对列表进行排序的好方法。我需要一个指针容器,因为还有其他几个依赖这些指针的数据结构。

那么我怎样才能选择一个更好的容器,它也对指针友好并允许通过查看指向类型的比较运算符进行排序?

澄清:我需要一个最适合场景的 stl 容器,并且可以成功地包装指针或引用。 (例如,我简要地读到 std::set 容器可能是一个很好的候选者,但我没有使用它的经验)。

当前的实现,基于以下答案:

struct SHafleEdgeComparatorFunctor
    {
        bool operator()(SHEEdge* lhs, SHEEdge* rhs)
        {
            return (*lhs) < rhs;
        }
    };

std::multiset<SHEEdge*, SHafleEdgeComparatorFunctor>    m_edges;

当然,SHEEdge 数据结构有一个重载的运算符:

bool operator<(SHEEdge* rhs) 
    {
        return this->GetCollapseError() < rhs->GetCollapseError();
    }

【问题讨论】:

  • 对我来说,听起来您已经回答了自己的问题:堆似乎是解决您问题的完美结构。
  • @NPE:我想问题就变成了; “是否有任何 STL(或 Boost)容器类似于堆?”...
  • @NPE: ty,我编辑了问题并为这个案例添加了说明。

标签: c++ data-structures stl


【解决方案1】:

我确实会使用std::set。您的要求中的棘手之处在于更新现有元素。

std::set 始终被排序。您必须使用有用的比较运算符将指针包装在一个类中,或者您必须将比较谓词传递给集合。

然后您会自动获得 sorted 属性,并且您会在恒定时间内移除最低元素。

您还可以更新日志复杂性的成本值:只需从集合中删除对象并重新添加即可。这将与排序容器一样快。

在集合中插入和删除速度很快。

【讨论】:

  • 我现在切换到set,但我会考虑并按照 MikePro 的建议/答案中温和地对矢量版本进行基准测试。谢谢
【解决方案2】:

我会开始使用像shared_ptr 这样的智能指针,而不是原始 指针(原始指针很好,例如,如果它们观察 指针,就像作为函数参数传递的指针,但是当您具有 所有权 语义时,例如在这种情况下,最好使用智能指针)。

然后,我将从std::vector 作为容器开始。

所以,试着改成vector&lt;shared_ptr&lt;MyObject&gt;&gt;

您可以衡量它与list&lt;shared_ptr&lt;MyObject&gt;&gt; 相比的性能。

(还要注意std::liststd::vector 有更多的开销,因为它是一个基于节点的容器,并且每个节点都有一些开销;相反std::vector 分配一个连续的内存块来存储它的数据,在这种情况下,shared_ptrs; 所以std::vector 也更“缓存友好”,等等)

总的来说,std::vector 提供了非常好的性能,作为“首选”容器是一个不错的选择。在任何情况下,您的里程数都可能非常大,最好的办法是衡量性能(速度),以便更好地了解您的具体情况。

【讨论】:

  • 这是怎么回答的?它会使用 MyObject 运算符吗?
  • @Alon:您可以使用std::sort()std::vector进行排序,并传递一个lambda来实现特定的自定义排序逻辑。
  • 与指针相同:) 但使用 shared_ptr 始终是一个可靠的建议
  • 是否可以保证在矢量容器上使用std::sort(),该容器的大部分元素已经按 w.r.t. 排序。到比较器将与教科书堆数据结构一样有效吗? (我不确定它是否会再次对向量进行 qsorts)。
  • @teodron:我只需编写一些代码并测量速度:有几个因素起作用,例如std::vector 在插入项目时更有效与基于节点的容器开销等相比,容量是否足够,所以我认为您应该考虑整个行为,而不仅仅是某些单个方面。
【解决方案3】:

如果我正确理解您的要求,那么您正在寻找要使用的正确容器。

确实,std::set 似乎是您想要做的事情的正确容器,但这取决于所有用例

  • 您是否需要 O(1) 访问元素?
  • 所使用的操作将产生最重要的成本?

std::set 使用键对元素进行排序并且不允许重复(如果您想要重复,请查看std::multiset)。添加元素时,它会自动插入到正确的位置。通常你不想使用原始指针作为键,因为对象可以为空。

另一种选择可能是使用std::vector&lt;std::shared_ptr&gt;&gt;,正如@MikePro 所说,将指针放在智能指针中是一个好习惯,以防止必须手动删除它们(并避免在发生异常时出现任何内存泄漏例如)。如果使用向量,则必须使用 std::sortstd::find 之类的函数,这些函数出现在 &lt;algorithm&gt; 标头或 std::vector::insert 中。

通常,此图像有助于找到您的容器。它并不完美(因为您必须比显示的内容多了解一点)但它通常可以很好地完成它的工作:

【讨论】:

  • +1 用于流程图 - O(1) 访问时间始终是理想的/很高兴没有人会拒绝。我在 set 和 vector 之间摇摆不定,但我决定目前使用 set 版本,看看它的效率如何。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 2015-08-07
  • 2018-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 2018-08-28
相关资源
最近更新 更多