我一直在编写一些代码来尝试从数组中创建一个完美平衡的树,但是当我遇到问题并且使列表大于3个元素时我得到错误"在评估期间堆栈溢出(循环递归) ?)&#34 ;.我是因为这是因为我的执行效率很低或者我犯了其他一些错误?感谢您的帮助,我们将非常感谢,代码如下。
ps - 我也意识到我应该使用fold_left作为辅助函数,但是直到这样做之后我才明白它
type 'a binary_tree =
| Empty
| Node of 'a * 'a binary_tree * 'a binary_tree;;
let length lst =
let rec aux acc = function
| [] -> acc
| x::xs -> aux (acc+1) xs
in
aux 0 lst;;
let mid lst =
let rec aux count = function
| [] -> None
| x::xs -> if (count=0) then Some x else aux (count-1) xs
in
aux ((length lst)/2) lst;;
let left lst =
let rec aux count acc = function
| [] -> []
| x::xs -> if (count=0) then acc else aux (count-1) (acc@[x]) xs
in
aux ((length lst)/2) [] lst;;
let right lst =
let rec aux count = function
| [] -> []
| x::y::xs -> if (count=0) then xs else aux (count-1) (y::xs)
in
aux (((length lst)/2)-1) lst;;
let rec createTree lst = match lst with
| [x] -> Node((Some x),Empty,Empty)
| xs -> Node((mid xs), (createTree(left xs)), (createTree(right xs)));;
答案 0 :(得分:3)
尽管实现效率很高,但递归循环仍然存在
从缺少的空案例[]
开始:从left [] = []
和right [] = []
开始,createTree []
被扩展为Node(mid [], createTree [], createTree [])
,这会导致堆栈溢出。
在效率方面,请注意,由于为每个元素计算的列表连接left
,您的较差函数为acc @ [x]
,其输入大小为二次而非线性。对于这种情况,通过在left
末尾反转列表,性能会更好。
另一方面,在left
函数中将mid
,right
,partition
组合在一起以避免重复可能是有意义的。
答案 1 :(得分:1)
您可以直接使用List.length
而不是自己定义;)
此外,如果您不特别需要保留元素的顺序,则可以通过获取列表的第一个元素来计算mid
,left
和right
值,并且如下所示拆分其余部分:
let split l =
let rec loop left right flag rest =
match rest with
| [] -> left,right
| h::t ->
if flag then loop (h::left) right (not flag) t
else loop left (h::right) (not flag) t
in loop [] [] true l
通过在每一步将flag
切换为not flag
,您可以将每两个元素中的一个元素发送到左侧列表中,将另一个元素发送到右侧列表中。
您的createTree
功能因此变为:
let rec createTree lst =
match lst with
| [] -> Empty
| h::t ->
let left,right = split t in
Node(h, (createTree left), (createTree right))
希望它会有所帮助:)