我试图用函子的不动点来实现一个二叉搜索树(或集合)。我定义了我的不动点如下:
newtype Fix f = In (f (Fix f))
out :: Fix f -> f (Fix f)
out (In f) = f
-- Catamorphism
type Algebra f a = f a -> a
cata :: (Functor f) => Algebra f a -> Fix f -> a
cata f = f . fmap (cata f) . out
为了生成二叉树,我使用了一个红黑树,如下所示:
data NodeColor = Red | Black deriving (Eq, Show)
data RedBlackTreeF a r = EmptyRedBlackTreeF | RedBlackTreeNodeF NodeColor r a r deriving (Eq, Show)
instance Functor (RedBlackTreeF a) where
fmap _ EmptyRedBlackTreeF = EmptyRedBlackTreeF
fmap f (RedBlackTreeNodeF color r1 a r2) =
RedBlackTreeNodeF color (f r1) a (f r2)
type RedBlackTreeF' a = Fix (RedBlackTreeF a)
二叉树的传统好处是能够通过选择是在左子树还是右子树中进一步搜索来减少搜索时间,如下所示(在伪代码中):
fun member (x, E) = false
| member (x, T (_, a, y, b)) =
if x < y then member (x, a)
else if x > y then member (x, b)
else true
如果要搜索的元素小于当前元素,则函数member
将向左移动,反之则向右移动。因此,它将搜索时间缩短为O(logn)
。
然而,在递归方案中,代数递归地应用于整个数据结构。我在这里写了一个member
代数:
memberPAlg :: Ord a => a -> RedBlackTreeF a Bool -> Bool
memberPAlg _ EmptyRedBlackTreeF = False
memberPAlg elem (RedBlackTreeNodeF _ left cur right) =
(elem == cur) || (left || right)
但是它似乎是O(nlogn)
而不是O(logn)
。有没有什么方法可以使用递归方案来选择性地递归以保存时间复杂度?我是不是想错了?
1条答案
按热度按时间z9zf31ra1#
由于懒惰,
left
和right
只有在你要求的时候才会被计算,所以,只要将当前节点与要搜索的值进行比较,就可以决定要进入哪个子树: