Der*_*aly 11 recursion f# functional-programming tail-recursion tail-call-optimization
当我写这个函数时,我知道我不会得到尾调优化.我仍然没有想出一个处理这个的好方法,并希望别人可以提供建议.
我有一棵树:
type Heap<'a> =
| E
| T of int * 'a * Heap<'a> * Heap<'a>
Run Code Online (Sandbox Code Playgroud)
我想要计算其中有多少个节点:
let count h =
let rec count' h acc =
match h with
| E -> 0 + acc
| T(_, value, leftChild, rightChild) ->
let acc = 1 + acc
(count' leftChild acc) + (count' rightChild acc)
count' h 0
Run Code Online (Sandbox Code Playgroud)
由于添加了子节点的计数,因此未进行优化.如果树有100万个节点,任何想法如何制作这样的东西?
谢谢,德里克
这是使用CPS实现计数.它仍然吹响了堆栈.
let count h =
let rec count' h acc cont =
match h with
| E -> cont (1 + acc)
| T(_,_,left,right) ->
let f = (fun lc -> count' right lc cont)
count' left acc f
count' h 0 (fun (x: int) -> x)
Run Code Online (Sandbox Code Playgroud)
也许我可以想出一些方法将树分割成足够的碎片,我可以计算而不会烧掉堆叠?
有人询问生成树的代码.它在下面.
member this.ParallelHeaps threads =
let rand = new Random()
let maxVal = 1000000
let rec heaper i h =
if i < 1 then
h
else
let heap = LeftistHeap.insert (rand.Next(100,2 * maxVal)) h
heaper (i - 1) heap
let heaps = Array.create threads E
printfn "Creating heap of %d elements, with %d threads" maxVal threads
let startTime = DateTime.Now
seq { for i in 0 .. (threads - 1) ->
async { Array.set heaps i (heaper (maxVal / threads) E) }}
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
printfn "Creating %d sub-heaps took %f milliseconds" threads (DateTime.Now - startTime).TotalMilliseconds
let startTime = DateTime.Now
Array.length heaps |> should_ equal threads <| "The size of the heaps array should match the number of threads to process the heaps"
let rec reMerge i h =
match i with
| -1 -> h
| _ ->
printfn "heap[%d].count = %d" i (LeftistHeap.count heaps.[i])
LeftistHeap.merge heaps.[i] (reMerge (i-1) h)
let heap = reMerge (threads-1) E
printfn "Merging %d heaps took %f milliseconds" threads (DateTime.Now - startTime).TotalMilliseconds
printfn "heap min: %d" (LeftistHeap.findMin heap)
LeftistHeap.count heap |> should_ equal maxVal <| "The count of the reMerged heap should equal maxVal"
Run Code Online (Sandbox Code Playgroud)
Joh*_*Joh 10
您可以使用延续传递样式(CPS)来解决该问题.请参阅递归递归 -由Matthew Podwysocki 继续传递.
let tree_size_cont tree =
let rec size_acc tree acc cont =
match tree with
| Leaf _ -> cont (1 + acc)
| Node(_, left, right) ->
size_acc left acc (fun left_size ->
size_acc right left_size cont)
size_acc tree 0 (fun x -> x)
Run Code Online (Sandbox Code Playgroud)
另请注意,在Debug版本中,禁用尾部调用优化.如果您不想在发布模式下运行,可以在Visual Studio中的项目属性中启用优化.
CPS是一个很好的通用解决方案,但您可能还想考虑显式使用堆栈,因为它会更快并且可以说更简单:
let count heap =
let stack = System.Collections.Generic.Stack[heap]
let mutable n = 0
while stack.Count > 0 do
match stack.Pop() with
| E -> ()
| T(_, _, heap1, heap2) ->
n <- n + 1
stack.Push heap1
stack.Push heap2
n
Run Code Online (Sandbox Code Playgroud)