haskell 使用退化(或任何递归方案)选择性地递归到二叉树的左或右子树

gijlo24d  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(120)

我试图用函子的不动点来实现一个二叉搜索树(或集合)。我定义了我的不动点如下:

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)。有没有什么方法可以使用递归方案来选择性地递归以保存时间复杂度?我是不是想错了?

z9zf31ra

z9zf31ra1#

由于懒惰,leftright只有在你要求的时候才会被计算,所以,只要将当前节点与要搜索的值进行比较,就可以决定要进入哪个子树:

memberPAlg :: Ord a => a -> RedBlackTreeF a Bool -> Bool    
memberPAlg _ EmptyRedBlackTreeF = False    
memberPAlg elem (RedBlackTreeNodeF _ left cur right) =    
   case compare elem cur of
     EQ -> True
     LT -> left
     GT -> right

相关问题