在ocaml中创建完全平衡的二叉树
我一直在写一些代码,试图从一个数组中创建一个完美平衡的树,尽管我在创建树并使列表大于3个元素时遇到了问题,但我得到了错误“求值期间堆栈溢出(循环递归?)。如果这是因为我的执行效率很低还是因为我犯了一些其他错误?感谢您的帮助,我们将不胜感激,代码如下 ps-我也意识到我应该使用fold_left来实现助手功能,但直到这样做之后,我才让他们明白在ocaml中创建完全平衡的二叉树,ocaml,Ocaml,我一直在写一些代码,试图从一个数组中创建一个完美平衡的树,尽管我在创建树并使列表大于3个元素时遇到了问题,但我得到了错误“求值期间堆栈溢出(循环递归?)。如果这是因为我的执行效率很低还是因为我犯了一些其他错误?感谢您的帮助,我们将不胜感激,代码如下 ps-我也意识到我应该使用fold_left来实现助手功能,但直到这样做之后,我才让他们明白 type 'a binary_tree = | Empty | Node of 'a * 'a binary_tree * 'a
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)));;
尽管实现效率很高,但递归循环仍然会停止 从缺少的空大小写
[]
:由于左[]=[]
和右[]=[]
,createTree[]
扩展到节点(mid[],createTree[],createTree[])
,从而导致堆栈溢出
在效率方面,请注意,最差的函数是left
,由于为每个元素计算的列表串联acc@[x]
,它的输入大小是二次的,而不是线性的。在这种情况下,如果将左
末尾的列表颠倒过来,性能会更好
另一点是,在
分区
函数中将左
、中
、右
组合在一起以避免一些重复是有意义的 尽管实现效率很高,但递归循环仍然会停止
从缺少的空大小写[]
:由于左[]=[]
和右[]=[]
,createTree[]
扩展到节点(mid[],createTree[],createTree[])
,从而导致堆栈溢出
在效率方面,请注意,最差的函数是left
,由于为每个元素计算的列表串联acc@[x]
,它的输入大小是二次的,而不是线性的。在这种情况下,如果将左
末尾的列表颠倒过来,性能会更好
另一点是,在
分区
函数中将左
、中
、右
组合在一起以避免一些重复是有意义的 您可以直接使用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
通过在每个步骤中将标志
切换到非标志
,您可以将每两个元素中的一个发送到左侧列表,将另一个发送到右侧列表。
因此,您的createTree
函数变为:
let rec createTree lst =
match lst with
| [] -> Empty
| h::t ->
let left,right = split t in
Node(h, (createTree left), (createTree right))
希望对您有所帮助:)您可以直接使用
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
通过在每个步骤中将标志
切换到非标志
,您可以将每两个元素中的一个发送到左侧列表,将另一个发送到右侧列表。
因此,您的createTree
函数变为:
let rec createTree lst =
match lst with
| [] -> Empty
| h::t ->
let left,right = split t in
Node(h, (createTree left), (createTree right))
希望能有所帮助:)谢谢你的帮助解释得很好也谢谢你的帮助解释得很好也谢谢你的帮助但我的想法是使用排序数组,然后生成一个平衡的二叉搜索树,而不仅仅是一个二叉树,但是将标志与单个列表一起使用仍然有帮助:)也谢谢您的帮助,但我的想法是使用排序数组,然后生成一个平衡的二叉搜索树,而不仅仅是一个二叉树,但是将标志与单个列表一起使用仍然有帮助:)