如何解决如何实现最佳的,纯功能的双端优先级队列?
Okasaki展示了如何使用O(1)
insert
和O(log n)
minView
编写纯功能优先级队列(某些版本还提供O(log n)
甚至{{1} } O(1)
。这些想法中的任何一个都可以扩展到双端优先级队列吗?Khoong和Leong(在我没有获得的论文中)提供了一种基于二项式的临时实现。堆,但从他们的论文中我可以看到,这种方法似乎很难持久化,因为它使用了父指针和兄弟指针。
解决方法
如左图所示,可以使用2–3个手指树来完成。特别是用半群注释的人
data MinMax k = MinMax
{ smallest :: !k,largest :: !k }
instance Ord k => Semigroup (MinMax k) where
MinMax min1 max1 <> MinMax min2 max2 = MinMax (min min1 min2) (max max1 max2)
可以用与fingertree
包定义优先级队列基本相同的方式,将这种带注释的手指树做成双端优先级队列(但要稍作调整以避免使用Monoid
)。可以使用与minView
相同的实现技术来改善maxView
和Data.Sequence.deleteAt
。
为什么使用Semigroup
而不添加中性元素使其成为Monoid
?这样,我们可以将MinMax
批注解包到树节点中,并避免在每个步骤中都有额外的间接操作以及额外的分配。
性能界限
-
insert
:摊销O(1)(注意:由于谨慎使用惰性,即使面对持久性,此界限也将成立)。最差情况O(log n)。请注意,fingertree
包仅声明O(log n)即可插入;这是我报告的文档错误,将在下一版本中予以纠正。 -
minView
/maxView
:最坏情况下的O(1)可以看到最小值/最大值;最糟糕的情况是O(log n)删除它。 -
meld
:最坏情况O(log(min(m,n)),其中m
和n
是队列的大小。
Hinze-Paterson风格的2–3手指树实际上比必要的多。一个手指的版本就可以解决这个问题,位数更少。
{-# options_ghc -funbox-strict-fields #-}
data Node k a
= Node2 !(MinMax k) !a !a
| Node3 !(MinMax k) !a !a !a
data Tree k a
= Empty
-- the child of a Zero node may
-- not be empty
| Zero !(MinMax k) (Tree k (Node k a))
| One !(MinMax k) !a (Tree k (Node k a))
最近几天我一直在努力充实。幸运的是,它非常简单。不幸的是,它需要大量的代码。根本的挑战是在2至3棵树中进行删除是相当重要的。手指树的版本增加了另一层复杂性。然后,整个内容必须写两次才能处理minView
和maxView
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。