【问题标题】:How to keep items sorted based on dynamic attribute?如何根据动态属性对项目进行排序?
【发布时间】:2009-07-28 18:45:20
【问题描述】:

我使用 STL std::multiset 作为指针的排序列表。排序顺序由所指向的项目的属性确定,类似于这个简化示例:

struct A
{
  int x;
};

bool CompareAPointers(const A* lhs, const A* rhs)
{ return lhs->x < rhs->x; }

std::multiset<A*, CompareAPointers> sorted_set;

复杂之处在于用于对集合进行排序的属性的值可能会发生变化(您可以在上面的示例中更改 A.x),这会导致排序顺序不正确:

A a1, a2;
a1.x = 1;
a2.x = 2;
sorted_set.insert(&a1);
sorted_set.insert(&a2);
a1.x = 3;

当相关属性发生变化时,我可以通过擦除和重新插入元素来保持列表的排序,但是簿记变得有点痛苦。我觉得我对这一切都错了。当排序顺序可以动态更改时,任何人都可以建议一种更好的方法来保持列表排序吗?这些变化在可预测的时间以可预测的方式发生,但我目前的方法感觉是错误的。

【问题讨论】:

    标签: c++ sorting stl


    【解决方案1】:

    Boost Multi-Index 支持对您想要的任何内容进行排序,并支持更改列表所依据的字段,尽管您不能再只输入a1.x=1,而是必须使用MultiIndex::replace()
    我想不出更快/更自然的方式来做到这一点,因为无论如何都必须删除和重新插入元素。

    【讨论】:

    • modify() 可能是更好的方法,因为元素无论如何都是非唯一的。主要的缺点是您必须将作业写入仿函数...
    • MultiIndex::replace() 是我认为最适合这种情况的建议。它在控制、效率潜力和为我照顾细节之间取得了适当的平衡。我不相信 modify() 是必要的,因为我存储的是指针而不是实际的对象,这使得元素复制变得微不足道。感谢您的建议!
    【解决方案2】:

    我会考虑改用已排序的std::vector。在您可以预见地为集合的成员之一修改x 的那些点之一,然后只需重新排序向量。这比必须移除和重新插入物品要干净一些。如果您经常修改单个集合成员的属性并重新排序,这可能会产生太多开销。如果您可能同时更改其中的许多属性,它会更有用。

    【讨论】:

    • 您可以将向量包装在另一个类中,该类还保留一个布尔值,当向量被修改时,该布尔值设置为 true。然后如果向量被访问但它没有排序,首先排序并返回值。
    【解决方案3】:

    正如其他人指出的那样,使用 std::set 或 std::multiset 并不能解决问题。

    您可能没有注意到,因为您使用了指针,但假设对象是不可变的(尽管在这种情况下,它意味着指针是 const,但不是指向的值)。

    因此,您不能(直接)使用会自动记账的标准容器。

    此时你有几种解决方案:

    • 您可以使用一个库,在这种情况下会想到 Boost.MultiIndex,尽管您必须学会使用它
    • 或者您可以将标准容器包装在专用类中(例如,您的集合)

    我认为两者都同样有效。由于操作非常简单,您可能还不想为此使用 Boost 库(学习曲线、集成等)。

    此外,您可以考虑使用“侵入式”容器。我的意思是您可以在此处使用“观察者”模式>>您的对象可以在每次其值更改时通知其容器,以便容器将其重新定位在其“新”正确位置(在内部使用 std::multiset) .

    如果效率是一个问题,我不会考虑对向量进行排序。每次更改单个对象时对一个完整的容器进行排序是一种浪费,您的擦除/插入方法效率更高。

    【讨论】:

    • 相信我,我注意到了不变性假设。这就是首先需要提出这个问题的原因。但我非常感谢您的意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多