[英]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.