除了优先队列的明显答案外,什么时候堆对我的编程冒险有用?
Answers:
每当您需要快速访问最大(或最小)项目时都可以使用它,因为该项目将始终是数组中的第一个元素或在树的根部。
但是,数组的其余部分保持部分未排序。因此,仅即时访问最大(最小)的物品。插入速度很快,因此这是处理传入事件或数据并始终可以访问最早/最大的一种好方法。
对于优先级队列,调度程序(需要最早的项目)等有用。
堆是一棵树,其中父节点的值大于其任何后代节点的值。
如果您将堆看作是按深度按线性顺序存储的二叉树,则首先是根节点(然后是该节点的子节点,然后是这些节点的子节点);那么索引为N的节点的子节点位于2N + 1和2N + 2。此属性允许按索引快速访问。而且由于通过交换节点来操纵堆,因此可以进行就地排序。
堆是用于允许快速访问最小或最大结构的结构。
但是,为什么要这样呢?您可以只检查add上的每个条目,以查看它是最小还是最大。这样,您始终可以始终拥有最小或最大的时间O(1)
。
答案是因为堆使您可以拉最小或最大并快速了解NEXT的最小或最大。这就是为什么它被称为优先队列。
假设您有一家医院,根据患者的年龄对其进行护理。年龄最大的人总是被优先参加,无论他/她何时排队。
您不能只跟踪最老的一个,因为如果您将他/她拉出,您将不知道下一个最老的。为了解决该医院问题,您实现了max heap。根据定义,该堆是部分排序的。这意味着您无法按年龄对患者进行排序,但是您知道年龄最大的患者总是排在最前面,因此您可以在固定时间内将患者拉出O(1)
并重新平衡日志时间O(log N)
。
假设您有一个整数序列,并且想要跟踪median
。中位数是位于有序数组中间的数字。
例:
[1, 2, 5, 7, 23, 27, 31]
在上述情况下,7
是中位数,因为包含较小数字的数组[1, 2, 5]
的大小与包含较大数字的数组的大小相同[23, 27, 31]
。通常,如果数组中元素的数量为奇数,则中位数为中间2个元素的算术平均值,例如(5 + 7)/2
。
现在,您如何跟踪中位数? 通过具有2个堆,一个最小堆包含的数字小于当前中位数,而一个最大堆包含的数字大于当前中位数。现在,如果这些堆始终保持平衡,则2个堆将包含相同数量的元素,或者一个堆比另一个堆多1个元素,最多。
在序列中添加新元素时,如果数字小于当前中位数,则将其添加到最小堆中,否则,将其添加到最大堆中。现在,如果堆不平衡(一个堆比另一个堆多一个元素),则从最大堆中拉出一个元素,然后添加到最小堆中。现在他们已经很平衡了。
堆的特征是它是一种将数据保持半序的结构。因此,在维持完整订单的成本和搜索随机混乱的成本之间进行权衡是一个很好的选择。该特性可用于许多算法,例如选择,排序或分类。
堆的另一个有用特性是可以从数组就地创建堆!