我很难理解tree_traverse函数及其功能,请有人解释。
(Peek和pop只是我所做的堆栈实现。)
type 'a tree = Leaf | Branch of ('a tree * 'a * 'a tree);;
let rec tree_traverse (t,mem,prim,seco) = match t with
| Leaf ->
if is_empty mem
then []
else tree_traverse (peek mem, pop mem, prim, seco)
| Branch (l,nd,r) ->
let mem1 = add (prim(l,r),mem) in
let mem2 = add (seco(l,r), mem1) in
nd :: tree_traverse (peek mem2, pop mem2, prim, seco)
一棵树的例子是
let t = Branch (Branch(Branch(Leaf,1,Leaf), 2, Leaf), 3,
Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)))
答案 0 :(得分:2)
此函数实现某种工作列表算法,它以某种顺序返回节点列表,该列表取决于prim
和seco
函数以及add
和pop
。
在递归过程中,prim
和seco
参数均未更改,因此可以从参数列表中将其删除。如果我们假设以下实现方式
let add (x,xs) = x :: xs
let pop (x::xs) = xs
let peek (x::xs) = x
let prim (x,y) = x
let seco (x,y) = y
let is_empty = function [] -> true | _ -> false
然后tree_traverse
函数将按深度优先顺序返回节点列表。
给出您的示例并将实现固定为上述指定的函数,我们现在可以跟踪该函数的执行:
tree_traverse Branch (Branch(Branch(Leaf,1,Leaf), 2, Leaf), 3,
Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)))
与Leaf
的情况不匹配,因此我们转到第二种情况,并将其解构为
| Branch (l,nd,r)) ->
(* l is bound to Branch (Branch(Leaf,1,Leaf), 2, Leaf) *)
(* nd is bound to 3 *)
(* r is bound to Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf)) *)
let mem1 = add (prim(l,r),mem) in
let mem2 = add (seco(l,r), mem1) in
nd :: tree_traverse (peek mem2, pop mem2, prim, seco)
我们将左子分支l
推入第一个堆栈mem1
,并将左和右子分支推入堆栈mem2
。然后,将3
放在结果之前,并递归到堆栈mem2
的顶部,同时放下它。
下一步,我们在第二个堆栈的顶部进行匹配,该堆栈包含右分支Branch (Branch(Leaf,5,Leaf), 6, Branch(Leaf,7,Leaf))
,我们再次进入第二种情况,
Branch(Leaf,5,Leaf)
绑定到l
变量,Branch(Leaf,7,Leaf)
绑定到r
。我们将6
添加到结果中,然后按l
,然后按并立即弹出r
,然后递归到其中。
在递归的第三步,我们用Branch(Leaf,7,Leaf)
进行调用,我们将7
添加到结果中,并将左右Leaf
推入堆栈。
在第四步,我们窥视Leaf
节点,最后进入第一种情况,我们在其中检查堆栈,如果不为空,则递归到顶部。在我们的示例中,堆栈包含同级的左Leaf
,然后是父节点的同级,等等。
您可以使用OCaml顶层(例如
#trace tree_traverse;;
tree_traverse (t,[],prim,seco);;
使用我上面提供的辅助函数的定义。