什么是表示红黑树的最有效方法?

时间:2014-02-27 16:36:45

标签: haskell

冈崎使用(基本上)

data Color = R | B
data RB a = L | T {-# UNPACK #-}!Color !(RB a) !a !(RB a)

我知道在C中,颜色通常以更加繁琐的方式处理以节省空间,做一些像指针的低位表示颜色(我想通常指针 a节点对其颜色进行编码,但也可以通过使节点中的左或右指针表示其颜色来模仿Okasaki的结构。

显然,在Haskell中,这种小小的变化是不可能的。那么,如何在Haskell中最有效地表示节点?

data RB' a = L | B !(RB a) !a !(RB a) | R !(RB a) !a !(RB a)

似乎可能具有合理的内存效率,但它似乎也可能使模式匹配相当冗长。

1 个答案:

答案 0 :(得分:2)

只能解压缩单个构造函数数据类型,并且无法为多态构造函数提供“泛型解包”。下面的树的单一类型构造实际上将使用指针标记进行存储。它有3个构造函数,其中一个是空的,不包含任何解引用。顺便说一句,GHC似乎有机会进行优化,但我不认为这样做。理论上data Foo = A | B | C | ... Z可以表示为26个不同的保留指针值。然而,我离题了。

data RB' a = L | B !(RB a) !a !(RB a) | R !(RB a) !a !(RB a)

上述类型将表示为标记指针,模式匹配将非常有效。我想当你提到记忆时,这就是你所指的。如果您知道a的值,则可以使用关联的数据类型(数据系列)来编写更有效的构造函数。关于这方面的一个很好的资源是Don Stewart的文章Self-optimizing data structures: using types to make lists faster

数据系列允许您表达类似于此的内容:

class AdaptRedBlackTree a where
  data RBTree a

  empty :: a
  insert :: a -> Tree a -> Tree a
  ...

instance RedBlackTree Int where
  data RBTree Int = RBEmptyInt 
                  | LInt (RBTree Int)
                         {-# UNPACK #-} Int
                         (RBTree Int) 
                  | RInt (RBTree Int)
                         {-# UNPACK #-} Int
                         (RBTree Int)

不幸的是,进一步拆包会很困难,但至少可以避免对Int值进行解除引用。