SML的新手,并尝试通过一系列练习来学习。我正在尝试编写的函数涉及将带有N个孩子的树展平。我的方法是简单地获取当前的NTreeNode
并将其值添加到要返回的列表中。然后采用第二个参数,即子列表,然后将其附加到另一个列表上,这就是我的队列。此队列将用作我剩下要处理的所有项目。
我试图通过将NTreeList
和我将以flattenNTree
的初始值返回的列表传递给辅助函数来实现此方法。
但是,当我尝试从队列中处理NTreeNode
时,它会给我返回NTree
,而我无法在其上使用first
/ second
函数,我需要从队列中返回一个元组。我只是不明白如何取回元组,我尝试使用NTreeNode
构造函数,但是即使那样也给了我NTree
的回馈。
我的问题是如何从已定义的NTree
数据类型中提取元组。
datatype NTree =
NTreeNode of int * NTree list
| EmptyNTree
;
fun first (a, _) = a;
fun second (_, b) = b;
fun processTree queue finalList =
if null queue
then finalList
else processTree ((tl queue)@(second(NTreeNode(hd queue)))) finalList@[first (NTreeNode (hd queue)) ]
;
fun flattenNTree EmptyNTree = []
| flattenNTree (NTreeNode x) = processTree (second x) [(first x)]
;
示例输入值:
val t =
NTreeNode (1, [
NTreeNode (2, [
NTreeNode (3, [EmptyNTree]),
NTreeNode (4, []),
NTreeNode (5, [EmptyNTree]),
EmptyNTree
]),
NTreeNode (6, [
NTreeNode (7, [EmptyNTree])
])
]);
答案 0 :(得分:3)
通过模式匹配将事情拆散比摆弄first
或tl
这样的选择器要容易得多。
反向累积列表并在完成后进行修复比重复添加到列表末尾更有效。
fun processTree [] final = reverse final
| processTree (EmptyTree::ts) final = processTree ts final
| processTree ((NTreeNode (v,t))::ts) final = processTree (ts @ t) (v :: final)
答案 1 :(得分:2)
您的processTree
函数缺少EmptyNTree
的大小写,并且您似乎在尝试调用NTree
和first
之前添加second
构造函数,而您就像在flattenNTree
中一样,需要删除它们。
可以通过将模式匹配应用于队列开头来解决这两个问题:
fun processTree queue finalList =
if null queue
then finalList
else case hd queue of
EmptyNTree => processTree (tl queue) finalList
| NTreeNode v => processTree (tl queue @ second v) (finalList @ [first v])
;
您可能还会考虑基于列表功能的实现(尽管结果的顺序不同):
fun flattenNTree t = case t of
EmptyNTree => []
| NTreeNode (n, nts) => n :: (List.concat (List.map flattenNTree nts));
答案 2 :(得分:0)
给出树的类型
datatype 'a tree = Node of 'a * 'a tree list
| Leaf
您可以折叠:
fun fold f e0 Leaf = e0
| fold f e0 (Node (x, ts)) =
let val e1 = f (x, e0)
in foldl (fn (t, e2) => fold f e2 t) e1 ts
end
并将其展平:
fun flatten t =
fold op:: [] t