将树的叶值更改为有序序列,同时保留树的结构

时间:2016-05-26 08:07:39

标签: haskell tree tree-traversal

给定是一个递归树结构

data Tree = Leaf Int | Node Tree Tree deriving Show

我想以保留树结构的方式对其进行规范化,但是使得叶子上的整数按深度顺序排列。我怎样才能做到这一点?我当前的设置代码如下所示:

myTree = Node (Leaf 3) (Node (Leaf 5) (Leaf 2))

myTree' = normalize myTree

-- preserve tree structure, but make Ints sequential in depths-first traversal
normalize :: Tree -> Tree
normalize = id -- todo: implement

main = do
    print myTree  -- prints      : Node (Leaf 3) (Node (Leaf 5) (Leaf 2))
    print myTree' -- should print: Node (Leaf 1) (Node (Leaf 2) (Leaf 3))

2 个答案:

答案 0 :(得分:1)

如果不使用monad,您可以编写一个函数映射带有某种状态的树

mapLRS :: (s -> Int -> (s, Int)) -> s -> Tree -> (Tree, s)
mapLRS f s (Leaf x  ) =
    let (s', x') = f s x
    in  (Leaf x', s')                  -- the mapped leaf and the new state
mapLRS f s (Node l r) =
    let (l', s' ) = mapLRS f s  l      -- the mapped left branch and the new state
        (r', s'') = mapLRS f s' r      -- the mapped right branch and the new state
    in  (Node l' r', s'')

现在

normalize :: Tree -> Tree
normalize = fst . mapWithStateLeftRight (\s _ -> (s + 1, s)) 1

使用monad可能更具可读性(f与使用state的简单性不一样。)

import Control.Monad.State

mapLRS :: (s -> (Int, s)) -> Tree -> State s Tree
mapLRS f (Leaf   x) = Leaf <$> state f
mapLRS f (Node l r) = Node <$> mapLRS f l <*> mapLRS f r

normalize :: Tree -> Tree
normalize tree = evalState (mapLRS (\s -> (s, s + 1)) tree) 1

答案 1 :(得分:1)

执行此操作的标准方法是将当前标签记录在monad状态:

import Control.Monad.State

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

normalize :: Tree -> Tree
normalize t = evalState (go t) 1 where

  go :: Tree -> State Int Tree
  go (Leaf _)   = Leaf <$> (get <* modify (+1))
  go (Node l r) = Node <$> go l <*> go r

此解决方案将状态初始化为1,然后遍历树,并在每次遇到Leaf时将当前标签放在返回的Leaf中并递增标签。

或者,我们可以派生Traversable的{​​{1}}实例:

Tree

这的工作方式相同,但请注意,它依赖于派生的{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-} import Control.Monad.State data Tree a = Leaf a | Node (Tree a) (Tree a) deriving (Show, Functor, Foldable, Traversable) normalize :: Tree a -> Tree Int normalize = (`evalState` 1) . traverse (\_ -> get <* modify (+1)) 实例具有正确的遍历顺序这一事实。当然,如果我们想要一些其他订单,那么我们就必须编写自己的遍历。