如何实现最佳的,纯功能的双端优先级队列?

问题描述

Okasaki展示了如何使用O(1) insertO(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相同的实现技术来改善maxViewData.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)),其中mn是队列的大小。

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棵树中进行删除是相当重要的。手指树的版本增加了另一层复杂性。然后,整个内容必须写两次才能处理minViewmaxView

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...