I've been trying to implement BinaryTree class in Ruby, but I'm getting the stack level too deep
error, although I don't seem to be using any recursion in that particular piece of code:
1. class BinaryTree
2. include Enumerable
3.
4. attr_accessor :value
5.
6. def initialize( value = nil )
7. @value = value
8. @left = BinaryTree.new # stack level too deep here
9. @right = BinaryTree.new # and here
10. end
11.
12. def empty?
13. ( self.value == nil ) ? true : false
14. end
15.
16. def <<( value )
17. return self.value = value if self.empty?
18.
19. test = self.value <=> value
20. case test
21. when -1, 0
22. self.right << value
23. when 1
24. self.left << value
25. end
26. end # <<
27.
28. end
Edit: My question has gone a little bit off track. The current code setting gives me the stack level too deep
error at line 8. However, if I employ Ed S.'s solution
@left = @right = nil
then the <<
method complains saying: undefined method '<<' for nil:NilClass (NoMethodError)
at line 22.
Could anyone suggest how to resolve this? My idea is that if I could somehow tell the BinaryTree
class that variables left
and right
are of instances of BinaryTree
(i.e. their type is BinaryTree
) it would all be well. Am I wrong?
A binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child. --Wikipedia. All trees start with a root, so does the Binary tree. For the above example, the top node with a 5 is the root.
A binary tree is made of nodes, where each node contains a "left" pointer, a "right" pointer, and a data element. The "root" pointer points to the topmost node in the tree. The left and right pointers recursively point to smaller "subtrees" on either side.
Generally binary tree's aren't sorted for you.
although I don't seem to be using any recursion in that particular piece of code:
Yet...
def initialize( value = nil )
@value = value
@left = BinaryTree.new # this calls initialize again
@right = BinaryTree.new # and so does this, but you never get there
end
That is infinite recursion. You call initilize
, which in turn calls new
, which in turn calls initialize
... and around we go.
You need to add a guard in there to detect that you have already initialized the main node and are now initializing leafs, in which case, @left
and @right
should just be set to nil
.
def initialize( value=nil, is_sub_node=false )
@value = value
@left = is_sub_node ? nil : BinaryTree.new(nil, true)
@right = is_sub_node ? nil : BinaryTree.new(nil, true)
end
To be honest though... why aren't you just initializing left and right to nil to begin with? They don't have values yet, so what are you gaining? It makes more sense semantically; you create a new list with one element, i.e., elements left and right don't yet exist. I would just use:
def initialize(value=nil)
@value = value
@left = @right = nil
end
1. class BinaryTree
2. include Enumerable
3.
4. attr_accessor :value
5.
6. def initialize( value = nil )
7. @value = value
8. end
9.
10. def each # visit
11. return if self.nil?
12.
13. yield self.value
14. self.left.each( &block ) if self.left
15. self.right.each( &block ) if self.right
16. end
17.
18. def empty?
19. # code here
20. end
21.
22. def <<( value ) # insert
23. return self.value = value if self.value == nil
24.
25. test = self.value <=> value
26. case test
27. when -1, 0
28. @right = BinaryTree.new if self.value == nil
29. self.right << value
30. when 1
31. @left = BinaryTree.new if self.value == nil
32. self.left << value
33. end
34. end # <<
35. end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With