Reputation: 90
I have been writing some code to try make a perfectly balanced tree from an array though i run into issues when I tree and make the list bigger than 3 elements i get the error "Stack overflow during evaluation (looping recursion?)". I was if this is was because my quite inefficient implementation or of some other mistake I have made? Thanks for any help it will be greatly appreciate, code below.
ps - I also realise I should have used fold_left for the helper functions but I did not them understand it till after doing this
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)));;
Upvotes: 1
Views: 1071
Reputation: 1586
You can use List.length
directly instead of defining it yourself ;)
Also, if you dont particularily need to preserve the order of your elements, you can compute your mid
, left
and right
values by taking the first element of a list, and splitting the rest as in the following :
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
By switching flag
to not flag
at every step, you send one in every two element into the left list, and the other into the right one.
Your createTree
function thus becomes :
let rec createTree lst =
match lst with
| [] -> Empty
| h::t ->
let left,right = split t in
Node(h, (createTree left), (createTree right))
Hope it will help :)
Upvotes: 1
Reputation: 18902
Notwithstanding the implementation efficiency, the recursive loop stems
from the missing empty case []
: since left [] = []
and right [] = []
, createTree []
is extended to Node(mid [], createTree [], createTree [])
which leads to the stack overflow.
On the efficiency side, note that your worse function is left
which is quadratic rather than linear in its input size due to the list concatenation acc @ [x]
which is computed for each elements. For this case, performance will be much better by reversing the list at the end of left
.
Another point, it could make sense to group together left
, mid
, right
in a partition
function to avoid some repetitions.
Upvotes: 3