我创建了一个递归二叉树,其中可以有无限个子代:
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]
编写为要操作的变量?
如果出现预期结果,将为True
或False
,但问题主要出在确定函数中列出的[Tree a]
的语法上。我尝试了多种编写方式,但始终会返回错误。
答案 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.Tree
和elem
是正确的选择。
另一方面,如果您要寻找的是带有两个子节点的实际二叉树,则对其进行定义并使其成为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