我有一组对象,每个对象都包含一个值。简化版如下:
struct Object
{
int value;
...
};
在某些操作过程中,该值可能会发生变化。不同的Object
s可能具有相同的值。
现在我需要将这些数据保存在容器中,以便我可以快速访问具有最大,第二最大,最小,第二最小值的对象。由于在某些操作期间值可能会发生变化,因此我希望更新不会非常昂贵。
确定Object
的数量。唯一会改变的是每个对象内部的值。
这种情况是否可以有一些好的数据结构?
我尝试使用set
/ multiset
作为键,但由于很多对象可能具有相同的值,因此效果不佳。
答案 0 :(得分:2)
你需要一个min-max heap,就像一个最小或最大的堆,但奇数行是他们孩子的最小行,偶数行是他们孩子的最大行。
你可以通过查看最小或最大节点的子节点来获得第二小或第二大节点,这些节点可以在恒定时间内找到,因为它们就在堆顶部。
你必须自己实施;几个星期前我自己做了,它并没有那么糟糕。
答案 1 :(得分:1)
您可以使用两个二进制堆来保持元素按升序和降序排序。然后,每个堆中的第一个元素是所有值的最小值/最大值。您可以通过比较每个堆的根的两个子项来获得第二个最小/最大值。因此,访问最小/最大元素将是O(1)。
您可以在O(log n)中的二进制堆中插入/删除/更新值。但是,由于您需要更新值,因此您需要自己实现siftUp / siftDown函数,因为std::push_heap
和std::pop_heap
函数不够。
您应该使用std::vector
来存储堆类中的元素,尤其是因为元素的总数是固定的。
这种方法的缺点是您需要存储两次数据。如果你的对象很大,你可以构建两堆指向真实元素的指针,以节省一些开销。但是如果你需要存储那些不会帮助的int
。
修改强> 最小 - 最大堆将阻止双重存储。请参阅Mehrdad's answer。
答案 2 :(得分:0)
我相信你可能会使用priority queue,这是一个类似于堆的概念。
自己实施比较对象,你就会好起来。您也可以拥有重复值,但请注意,对于相同的元素,它不会是稳定的算法,所以不要依赖它。
另请注意,这是一个适配器。您可能希望尝试使用不同的容器来查看它们是否符合您的要求(您的复杂性要求是什么?)
答案 3 :(得分:0)
double-ended queue(std::deque
)怎么样?
您可以快速访问最高值和最低值,std::sort
可以根据需要重新确定正确的订单。唯一的事情是它在更新时不会“自我排序”。但是,如果你很聪明,你可以最大限度地减少重新排序的需要,直到你修改一个“特殊情况”的顺序。
priority queue
的问题是你需要一个用于最大值,一个用于最小值。即使这样,您也无法在不首先弹出顶部值的情况下访问第二个顶级值。你的案例很专业,所以包裹deque
对你来说是最好的解决方案。