【问题标题】:tree with defined Type in haskell在haskell中定义类型的树
【发布时间】:2014-04-19 18:15:41
【问题描述】:

我正在尝试从 pre/poststoreder traversals 构造一棵树。我的树类型如下:

        data Tree = Emptytree | Node Integer [Tree]

我是函数式编程的新手。所以我在构建基本案例和递归时遇到了一些困难。我的函数将是这样的:

           ListToTree :: [Integer] -> [Integer] -> Tree

我构建了一些算法,但无法使其符合语言要求。 我的算法很简单:我取第一个列表(前序遍历列表)的每个元素,然后检查它在第二个列表中的位置。举个例子吧:

                1                       
             /     \    
          2          5
         /  \
       3      4

这个Tree遍历的前序如你所知[1,2,3,4,5]

这个Tree遍历的后序如你所知[3,4,2,5,1]

首先,我查看第一个列表的第一个元素,它是 1,然后我查看它在第二个列表中的位置,它是最后一个,所以我将它添加到我的树中。然后我检查树的下一个元素,它在第二个列表中是 2,它在 1 的左侧,这意味着它是它的子元素。然后 3 在 2 的左边(在第二个列表中)这意味着它也是 2 的儿子然后我看 4 它在 2 的左边它是 2 的儿子,最后 5 它在左边1 它是一个的孩子(因为它在 2 的右边它不是 2 的孩子)。

我试图实现它。我编写了帮助函数来确定 Node 是否有孩子。我在我的函数中也使用了计数器所以实际上我的函数是这样的:

           ListToTree :: Integer -> [Integer] -> [Integer] -> Tree
           {-First Stands for counter ,2nd preorder, 3rd postorder-}

我的基本条件是:

                 1. is about if list are Emptytree return Emptytree
                 2. is about if counter== length-1 return Node element [Emptytree]

我的主要问题部分在我的递归部分:

  ListToTree counter a b  
    | hasChild b counter == 1 = Node ( Element ) [ListToTree (1+counter) a b]
    | hasChild b counter == 0 = Node ( Element ) [Emptytree]
        {-My problematic part if node has no Child what I must change here-}
        {-Or what are your suggestions-}

我需要帮助来改进我的算法。任何形式的帮助或 cmets 将不胜感激。

【问题讨论】:

  • 是二叉树吗?如果不是,N在哪里定义?
  • 它不是二叉树,它是 N 叉树,每个节点可以有不同数量的子节点
  • 是否为非二叉树定义了后序和前序扫描?
  • 你说的定义是什么?您可以使用前序和后序遍历来遍历所有 N 叉树

标签: haskell syntax tree functional-programming


【解决方案1】:

haskell 的美妙之处在于您通常不需要计数器。通常只进行模式匹配就足够了。

我将为[Tree] 提供解决方案,因为这需要较少的案例。如果您想要单个 Tree 的解决方案,您可以在包装函数中引入一些案例。

listToTree :: [Integer] -> [Integer] -> [Tree]
listToTree [] [] = []
listToTree (x:xs) ys = go where
    fstSubTreePost = takeWhile (/=x) ys -- all the elems of 1. subtree except x
    fstSubTreeLength = length fstSubTreePost
    fstSubTreePre = take fstSubTreeLength xs
    -- this will recursively compute the first subtree
    fstTree = Node x (listToTree fstSubTreePre fstSubTreePost)
    -- the next line will recursively compute the rest of the subtrees
    rest = listToTree (drop fstSubTreeLength xs) (drop (fstSubTreeLength+1) ys)
    go = fstTree : rest

【讨论】:

  • 这很好,但它提供了一些额外的空列表,如果我能找到摆脱它们的方法会更好
【解决方案2】:

鉴于前序和后序是 [Integer],可能有零个或一棵或多棵树返回这些遍历。例如,遍历 [1,1,1] 和 [1,1,1] 有两个可能的树。使用“mLast”和“splits”辅助函数,可以定义一个简短的“listToTrees”来处理可能的“Forest”解析。然后很容易将“listToTree”定义为产生可能的单个“树”解析的特殊情况。

module PPT where

import Data.List

data Tree a = Emptytree | Node a (Forest a)
    deriving Show

-- | A list of sibling trees, in left to right order
type Forest a = [Tree a]

-- | Returns a list of all valid trees that produce the given pre-order and post-order traversals.
--
-- If the input cannot be parsed into a Tree then results is an empty list.
listToTree :: [Integer] -> [Integer] -> [Tree Integer]
listToTree [] [] = [Emptytree]  -- base case
listToTree [] _ = []            -- detect length mismatch
listToTree (x:xs) yAll = case mLast yAll of
    Just (ys, y) | x==y -> map (Node x) (listToTrees xs ys) -- pre-order start == post-order end
    _ -> []

-- | Given pre-order and post-order traversals of a forest, return a list of possible parsings.
listToTrees :: [Integer] -> [Integer] -> [Forest Integer]
listToTrees [] [] = [ [] ]      -- base case
listToTrees [] _ = []           -- detect length mismatch
listToTrees (x:xs) ys = concatMap build (splits x ys) -- for each copy of 'x' in ysAll
  where
      build (belowX', _x', rightOfX') =
          let (belowX, rightOfX) = splitAt (length pre) xs
          in [ Node x kids : sibs
             | kids <- listToTrees belowX belowX'
             , sibs <- listToTrees rightOfX rightOfX' ]

-- | Safely split a non-empty into the initial portion and the last portion
mLast :: [a] -> Maybe ([a], a)
mLast [] = Nothing
mLast ys = Just (init ys, last ys)

-- | At each position for the given element 'x', split the input list 'ys' into (pre, x, post)
-- portions.  The output has a tuple for each copy of 'x' in the input list 'ys'.
--
-- This could be better optimized to avoid (++), or changed to a zipper
splits :: Eq a => a -> [a] -> [ ([a], a, [a]) ]
splits x ysIn = unfoldr go ([], ysIn)
  where
    go (pres, ys) =
        case span (x /=) ys of
            (_, []) -> Nothing
            (pre, x':post) -> Just ((pres ++ pre, x', post), (pres++pre++[x'], post))

-- | test1 has a single possible parsing
test1 :: ([Integer], [Integer])
test1 = ( [1, 2, 3, 4, 5]
        , [3, 4, 2, 5, 1] )

-- | test2 has two possible parsings
test2 :: ([Integer], [Integer])
test2 = ( [1, 2, 1, 2]
        , [2, 1, 2, 1] )

main :: IO ()
main = do
    mapM_ print (uncurry listToTree test1)
    mapM_ print (uncurry listToTree test2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2011-08-28
    • 1970-01-01
    相关资源
    最近更新 更多