在函数中使用递归二叉树列表遍历数据类型

时间:2019-04-10 13:51:08

标签: haskell

我创建了一个递归二叉树,其中可以有无限个子代:

data Tree a = Leaf a
            | Node [Tree a]

我的问题是在创建函数时要遍历树的语法。

说我想做些简单的事情,例如给参数1,然后找出Bool是否在树中出现1。当Node[Tree a]而不是Node [Leaf root Leaf]时,函数定义出现了问题。我不习惯该函数在变量中调用列表。

以下是使用更简单的递归数据类型的方法:

occs :: Eq a => a -> Tree a -> Bool 
occs x (Leaf y) = x == y
occs x (Node left y right) = x == y || occs x left || occs x right

但是,(Node left y right)不再合适,因为Node现在是列出的树[Tree a]。如何将列出的树[Tree a]编写为要操作的变量?

如果出现预期结果,将为TrueFalse,但问题主要出在确定函数中列出的[Tree a]的语法上。我尝试了多种编写方式,但始终会返回错误。

2 个答案:

答案 0 :(得分:3)

您只想递归检查任何分支(这就是我在列表中称为树)的分支是否包含x。幸运的是,Prelude包含一个函数any,使此操作变得非常简单:

occs :: Eq a => a -> Tree a -> Bool 
occs x (Leaf y) = x == y
occs x (Node branches) = any (occs x) branches

({any也很容易实现,如果需要的话)

答案 1 :(得分:0)

由于罗宾·齐格蒙德(Robin Zigmond)对您的问题给出了答案:“如何将列出的树[Tree a]作为变量进行操作?”,我将尝试以不同的方式回答。

  

我创建了一个递归二叉树,其中可以有无限个子代:

data Tree a = [...]

然后它不是二进制文件,而是 n -ary。

此精确类型已经存在于Data.Tree模块下的containers包中。

Data.Tree为此定义了许多类型类实例,其中一个是Foldable,并且您正在编写的函数已经在Data.Foldable中,名称为{{ 3}},其类型为:

elem :: (Eq a, Foldable t) => a -> t a -> Bool

因此,如果您选择的数据类型是一棵 n ary树,则Data.Treeelem是正确的选择。


另一方面,如果您要寻找的是带有两个子节点的实际二叉树,则对其进行定义并使其成为Foldable的实例将以相同的方式为您提供elem

{-# LANGUAGE DeriveFoldable #-}

data BinaryTree a
  = Leaf
  | Node a (BinaryTree a) (BinaryTree a)
  deriving (Foldable)

-- now `elem` comes for free

编辑:遵循amalloy的建议,而是派生了Foldable实例。

但是由于elem仅受Eq a而非Ord a的约束,因此您无法获得 O(log n)查找一棵二元 search 树,因此如果需要,您必须将其命名为其他名称:

occs :: Ord a => a -> BinaryTree a -> Bool
occs _ Leaf = False
occs x (Node y left right) =
  case x `compare` y of
    LT -> occs x left
    EQ -> True
    GT -> occs x right
相关问题