Haskell二叉树函数(图)

时间:2010-05-03 07:15:07

标签: algorithm haskell binary-tree

如何定义一个Haskell函数,它将函数应用于二叉树中的每个值?所以我知道它类似于map函数 - 它的类型是:

mapT :: (a -> b) -> Tree a -> Tree b

但那是关于它......

4 个答案:

答案 0 :(得分:9)

您可以声明类Functor的实例。这是允许映射函数的数据类型的标准类。请注意fmap类型与mapT类型的相似程度:

class Functor f where
  fmap :: (a -> b) -> f a -> f b

我们假设您的树被定义为

data Tree a = Node (Tree a) (Tree a) | Leaf a
  deriving (Show)

然后你可以用这种方式声明Functor的实例:

instance Functor Tree where
  fmap f (Node l r) = Node (fmap f l) (fmap f r)
  fmap f (Leaf x) = Leaf (f x)

您可以使用它:

main = do
  let t = Node (Node (Leaf 1) (Leaf 2)) (Leaf 3)
  let f = show . (2^)
  putStrLn $ "Old Tree: " ++ (show t)
  putStrLn $ "New Tree: " ++ (show . fmap f $ t)

输出:

Old Tree: Node (Node (Leaf 1) (Leaf 2)) (Leaf 3)
New Tree: Node (Node (Leaf "2") (Leaf "4")) (Leaf "8")

您还可以为方便起见进行定义:

mapT = fmap

当然,您可以在没有类型类的情况下执行此操作,但如果您使用标准函数(每个人都知道fmap的通常行为),它会使代码对其他代码更具可读性。

答案 1 :(得分:6)

我会假装这是作业而不是放弃所有的答案。如果我弄错了,我道歉。

可能您的Tree类型看起来像这样:

data Tree a = TreeNode a (Tree a) (Tree a) | EmptyNode

这里有两种情况,您需要为每种情况编写一个mapT实现:

  • 内部节点TreeNode,其值为a,并且具有左子项和右子项。在这种情况下需要做什么?
  • 终端节点EmptyNode。在这种情况下需要做什么?

答案 2 :(得分:4)

地图功能的基本格式适用于两者。让我们看一下列表的map函数的定义:

map f (x:xs) = f x : map f xs
map _ []     = []

我们可以这样概括:

  1. 您获取数据结构中的第一个值
  2. 将功能应用于它
  3. 使用剩余的数据结构递归调用map函数
  4. 将修改后的值和递归调用都传递给您的类型的构造函数。
  5. 当你到达终点时,停止递归
  6. 你真正需要的只是看看你的构造函数,地图函数应该到位。

答案 3 :(得分:1)

有趣的问题,如果输入和输出应该是排序二进制树。如果您只是天真地遍历树并应用该函数,则可能不再对输出树进行排序。例如,考虑函数是否是非线性的,如

f(x) = x * x - 3 * x + 2

如果输入有{1,2,3,4},则输出将具有{2,0,0,2}。输出树是否应仅包含0和2?

如果是这样,您可能需要在删除并处理输入树时迭代地构建输出树。