对于可能有相同问题的其他人,我将用我迄今为止发现的内容来回答自己:
最小-最大堆本质上是三合一的堆,具有共享的叶级别。
min1 <--- one min heap, first level
/ \
mi2 mi3 <--- third level
/ \ / \
m5 m6 m7 m8 <--- fifth level
/\ /\ /\ /\
a b c d e f g h <--- leaf level (here: sixth level)
\/ \/ \/ \/
x1 x2 x3 x4 <--- fourth level
\ / \ /
max1 max2 <--- two max heaps, second level
(重要提示:这不准确,因为堆的扇出为 4!另外,这是逻辑顺序,而不是内存布局,它按层次交错堆)叶级别的对象属于所有三个堆,这是元素从堆的最小部分过渡到最大部分的地方。
现在可以计算最小堆和最大堆的大小,使用部分排序(例如快速选择)对数据进行分区并单独批量加载这三个部分。但是,quickselect 的成本已经与您希望整个批量加载的成本一样高(部分订购数据集)!批量加载和批量修复(!)堆的另一种明显方法是查看较小的子堆。在常规最小堆中,您将查看三个元素 a、b、c 的原子堆,并确保 a 是最小的。在这里,我们可以查看高度为 4 的堆,即 15 个元素:
min1
/ \
max1 max2
/ \ / \
m1 m2 m3 m4
/\ /\ /\ /\
a b c d e f g h
并确保 min1 是最小的,max1 和 max2 是最大的两个,m1-m4 是接下来的 4 个最大的,并且分两级爬上树(即仅 min 级)
或者我们可以查看大小为 7(3 个级别)的堆并识别最小和最大类型
min1 max1
/ \ / \
max1 max2 min1 min2
/\ /\ /\ /\
a b c d a b c d
确保对于最低级别我们有第一种类型,对于最高级别我们有第二种类型。然后我们需要遍历所有级别。
但也许更好的解决方案是使用区间堆。这本质上也是一个交错的最小和最大堆。但是,它们是对称交错的并且具有相同的大小。它们似乎实现起来要简单得多,并且可以解释为如下所示的堆:
min1,max1
/ \
min2,max2 min3,max3
有关批量加载的详细信息,请参阅原始区间堆出版物。
因此,如果您对可批量加载的最小最大堆感兴趣,请考虑查看区间堆!有人说它们无论如何都优于最小最大堆;它们密切相关,应该更容易实施。特别是,没有明显的理由为什么最小最大堆应该表现得更好,如果详细的复杂性分析表明它们在需要的比较和交换中的一个常数因子表现更差(因为据我可以天真地说,一个 min-max-heap 需要更多的比较来验证堆的正确性)。