[英]C++ Priority Queue - ordering intervals
最初给定一个时间间隔。 每次,我们选择最大的间隔并将其分成两半。 如果有平局,那么我们选择起点最低的区间。
例如 - [0,9] 第一次拆分 - P1 [0,4] 和 P2 [4,9]
对于第二次拆分:dist(P1) = 3 => 如果选择 P1,新的间隔将是 [0,2] 和 [2,4]。 dist(P2) = 4 => 如果选择 P2,新的区间是 [4, 6] 和 [6,9] 在这两种情况下,我们都必须创建距离为 1 的子区间。所以,这是平局。 并且,我们选择 P1 为 P1 < P2。
[0,2], [2, 4], [4, 9]
第三次拆分:[0,2]、[2, 4]、[4,6]、[6,9]
第四分裂:有平局,s0,选[0,2] [0,1], [1,2], [2,4], [4,6], [6, 9]
第五分裂:[0,1], [1,2], [2,3], [3,4], [4,6], [6,9]
可能的候选人:[4,6]
但是,我总是把 [1,2] 放在首位。
#include <iostream>
#include <queue>
using namespace std;
int main()
{
auto dist{ [](const auto & p) {
return p.second - p.first - 1;
} };
auto comp{
[&dist](const auto & p1, const auto & p2) {
if (abs(dist(p1) - dist(p2)) <= 1) {
return p1.first > p2.first;
}
return dist(p1) < dist(p2);
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> maxQ{comp};
maxQ.push({ 0, 9 }); // initial interval
for (int i{ 0 }; i < 5; ++i) {
auto ii{ maxQ.top() };
maxQ.pop();
int mid = (ii.first + ii.second) / 2;
maxQ.push({ ii.first, mid });
maxQ.push({ mid, ii.second });
}
while (!maxQ.empty()) {
auto& ii{ maxQ.top() };
cout << ii.first << " : " << ii.second << endl;
maxQ.pop();
}
}
我得到以下 output:
1 : 2
6 : 9
0 : 1
2 : 3
3 : 4
4 : 6
IMO,1:2 间隔不应该在顶部。 有人可以在这里帮助我,为什么会这样。
事实证明,这个问题更多地与优先级队列比较器的设计方式有关,请参阅The reason of using `std::greater` for create min heap via `priority_queue`
它的要点是,当比较两个节点时,如果比较器返回 true,则 p1 将低于 p2。 所以一个基本的“>”比较器,顶部有较小的节点,底部有较大的节点。
为了可视化这个问题,我在调试器中运行了它,这是将 (1,2) 置于 (6,9) 之上的时刻。 这是优先级队列的当前 state:
2 : 4
6 : 9
4 : 6
0 : 1
1 : 2
我们看到 (2,4) 在前面 (6,9),这是预期的,因为我们的比较 function 说 (2,4) < (6,9) 如上所述。
然后,代码会弹出优先级队列的顶部,这意味着将 (2,4) 替换为新的最大间隔。 C++ 中的优先级队列是如何做到这一点的,它们是交换堆的第一个元素和最后一个元素,然后将其大小减 1(因此我们丢失了原始的第一个元素)。
所以在交换和减小大小之后,我们的堆看起来像这样:
1 : 2
6 : 9
4 : 6
0 : 1
然后,由于之前认为最小的元素现在位于队列的顶部,我们需要找到它的正确位置。
所以 (1,2) 将查看它的孩子 (6,9) 和 (4,6),看看哪个更重要。
对于我们的比较运算符,(4,6) 是更重要的节点。
然后它将 (1,2) 与前两个节点中最重要的节点 (4,6) 进行比较,以查看是否需要执行交换以使队列有效。
然后它发现 (1,2) 更重要,因为 1 < 4。因此,(1,2) 停留在它的位置,我们剩下:
1 : 2
6 : 9
4 : 6
0 : 1
我们可以清楚地看到[1,2]
在[4,6]
之前排序,通过将其插入您的比较器:
comp([1,2], [4,6])
if (abs(dist([1,2]) - dist([4,6])) <= 1) { // abs(0 - 1) <= 1 or 1 <= 1
return 1 > 4; // false
}
return dist([1,2]) < dist([4,6]); // not reached
只有您可以更正比较器以实现您的目标,但是如果您希望[1,2]
在[4,6]
之后排序,则现有代码是错误的。
不过,根据您的描述,您可以猜测一下:
if (abs(dist(p1)) == abs(dist(p2)))
但是我会 go 到一定的长度,以确保您的订购是严格弱的,因为它必须是容器。 在周围多撒一些abs
可能会有所帮助。
总的来说,这是一个相当复杂的比较器,乍一看并不容易理解。
我认为这是因为间隔的顺序不严格。 例如 P1(0,1)、P2(4,6) 和 P3(6,9)
P1 应该在 P2 之前。 P2 应该在 P3 之前。 P3 应该在 P1 之前。
太疯狂了。 我怎么能在这里设置严格的配对排序?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.