该函数应将图层中参数树的标记打印为图层列表。每个层中的节点和叶标记从左到右列出,也就是说,它是图层的最左边节点,列表的第一个元素,最右边的节点是列表的最后一个元素。 Ord类型的参数指示是否要发布从最小层到最大层(TopDown)的升序或从最大到最小层(BottomUp)的降序的层
data Tree = Leaf Integer | Node Integer Tree Tree
type Layer = [Integer]
data Ord = BottomUp | TopDown
wLayer :: Tree -> Ord -> [Layer]
示例1:我们使用参数
来调用函数wLayer
wLayer(节点1(节点2(叶21)(叶22))(节点3(叶31)(叶32)))TopDown
结果:[[1],[2,3],[21,22,31,32]]
示例2: wLayer(节点1(节点2(叶21)(叶22))(节点3(叶31)(叶32)))BottomUp 结果:[[21,22,31,32],[2,3],[1]]
我该如何实现这个呢?
修改
data Tree = Leaf Integer
| Node Integer Tree Tree
type Layer = [Integer]
data Ord = BottomUp | TopDown
writeLayer :: Tree -> Ord -> [Layer]
writeLayer Leaf x = [x]
writeLayer (Node x lt rt) BottomUp = (writeLayer rt BottomUp) ++ [x] ++ (writeLayer lt BottomUp)
writeLayer (Node x lt rt) TopDown = [x] ++ (writeLayer lt TopDown) ++ (writeLayer rt TopDown)
这是我的程序,但是我怎么能解决它?
答案 0 :(得分:2)
一些提示:
Tree
是Leaf
的情况很简单BottomUp
和TopDown
之间的差异似乎是您是否反转Layer
s Tree
是Node
时,您必须在子树上进行递归并以某种方式合并结果编辑:好的,让我们专注于其中的第一个。
您对此案例的等式是
writeLayer Leaf x = [x]
首先,Leaf x
需要在括号中,因为它是一个Tree
值。
writeLayer (Leaf x) = [x]
其次,该等式需要反映writeLayer
采用两个参数(如上所述,它只需要一个)。使用Leaf
值,我们不关心返回结果的顺序 - 我们以任何一种方式给出相同的答案 - 但我们仍然必须采用参数。我们使用_
表示我们不关心参数,并且不会使用它。
writeLayer (Leaf x) _ = [x]
第三,[x]
是Integer
s的(单个元素)列表,但我们应该返回Layer
个列表。我相信你可以弄清楚如何解决这个问题。
最后,请注意计算机给您的错误消息。了解他们。
答案 1 :(得分:2)
这是实现此目的的简单方法。它接受一个级别的所有节点并从中提取整数值,然后对这些相同节点的所有子节点进行递归。之后,您匹配Ord
以确定是否需要撤消列表。
writeLayer t o =
case o of
BottomUp -> reverse $ makeLayer [t]
TopDown -> makeLayer [t]
where
extract (Node i _ _) = i
extract (Leaf i) = i
children (Node _ a b) = [a, b]
children _ = []
makeLayer [] = []
makeLayer ts = map extract ts : (makeLayer $ concat $ map children ts)
答案 2 :(得分:1)
保罗的回答给出了水平顺序遍历的核心定义 - 展开列表。 (练习:使用makeLayer
写Data.List.unfoldr
。)这也是我最喜欢的方式;见The Underappreciated Unfold。
但它也可以递归地完成 - 作为树上的折叠。这些是通过类似于列表上的foldr
来定义的,如下所示:
foldt :: (Integer->a) -> (Integer->a->a->a) -> Tree -> a
foldt f g (Leaf n) = f n
foldt f g (Node n t u) = g n (foldt f g t) (foldt f g u)
然后,通过简单的树折给出水平顺序遍历,可能reverse
:
wLayer :: Tree -> Order -> [Layer]
wLayer t o = (if o==BottomUp then reverse else id) (foldt single glue t)
我冒昧地将你的标志类型Order
重命名为一个名称冲突的空白,并使其成为Eq
的实例:
data Order = BottomUp | TopDown deriving Eq
函数single
进行叶子的水平顺序遍历:
single :: Integer -> [Layer]
single n = [[n]]
而glue
将标签和两个孩子的遍历组合到一个节点的遍历中:
glue :: Integer -> [Layer] -> [Layer] -> [Layer]
glue n x y = [n] : longzipwith (++) x y
关键因素是函数longzipwith
,它类似于zipWith
,除了(i)结果的长度是较长参数的长度,而不是较短的,因此(ii)二元运算符必须是a->a->a
:
longzipwith :: (a->a->a) -> [a] -> [a] -> [a]
longzipwith f (a:x) (b:y) = f a b : longzipwith f x y
longzipwith f x [] = x
longzipwith f [] y = y
答案 3 :(得分:0)
这是我的程序
data Tree = Leaf Integer
| Node Integer Tree Tree
type Layer = [Integer]
data DOrd = BottomUp | TopDown
writeLayer :: Tree -> DOrd -> [Integer]
writeLayer (Leaf x) _ = [x]
writeLayer (Node x lt rt) BottomUp = (writeLayer rt BottomUp) ++ [x] ++ (writeLayer lt BottomUp)
writeLayer (Node x lt rt) TopDown = [x] ++ (writeLayer lt TopDown) ++ (writeLayer rt TopDown)
呼叫:
*Main> writeLayer (Node 1 (Node 2 (Leaf 21) (Leaf 22)) (Node 3 (Leaf 31) (Leaf 32))) TopDown
[1,2,21,22,3,31,32]
*Main> writeLayer (Node 1 (Node 2 (Leaf 21) (Leaf 22)) (Node 3 (Leaf 31) (Leaf 32))) BottomUp
[32,3,31,1,22,2,21]
但我想先采取:[[1],[2,3],[21,22,31,32]]
第二:[[21,22,31,32],[2,3],[1]]