Binary Tree November 16th, 2007
Binary tree is important topic in computer science, especially in data structures field. The important characteristics are fast insertion, retrieving sorted data rapidly. Binary tree can be described like this. Every node has two leaves nodes. One or both of these two leaves nodes maybe be empty or using computer science terminology, null. Some people like to call these two leaves nodes as children nodes. Every binary tree has one root node. So there is no ambiguity for choosing starting point. After that you will have two choices every time you want to continue your journey traveling down the tree, except when the child leaf is empty or null.
We can use binary tree as efficient data structures for sorted data. When sorted data is implemented with binary tree data structures, we can rapidly store sorted data and rapidly retrieve sorted data. If you learn C/C++ and Pascal, most likely you will encounter lesson sorting data using binary tree. In C/C++ the node is implemented with struct with three fields. The first will be holder for value/data. The second and third will be pointer to this struct type data. In Ruby you can use Struct or Class as node. You don’t have pointer in Ruby but you use object reference as replacement. Most likely you will not use binary tree as data structures for sorted data in Ruby. But there are some cases that make binary tree suitable for data structures in Ruby.
One of case that makes binary tree useful is this quiz. Binary tree is suitable data structure for database in this quiz. You put questions in interior nodes and another questions or the answers in children nodes. Using object reference give a little headache when solving this quiz. In the code given later in this post, if you remove the clone method from leaf object, it will screw up. Because if you don’t use clone method, the reference in other leaves nodes maybe lost when you update the relevant leaf node.

Tree means recursive function. The recursive function in my code for the quiz is play. When you choose ‘no’ for the answer, it will call function play with leaf.no. When you choose ‘yes’ for the answer, it will call function play with leaf.yes.
There is other way to implement binary tree beside using struct like type. Using array. There is rule for finding children or parent for specific index. For index i, its children are 2i + 1 and 2i + 2. For index i, its parent is (i – 1) / 2. But it is more complicated than using struct type data.
So here is the code:
# solve ruby quiz # 15 http://www.rubyquiz.com/quiz15.html
# our struct
Animal = Struct.new(:que_name, :yes, :no)
# in the beginning, there is only elephant
elephant = Animal.new('an elephant', nil, nil)
@root = Animal.new('is it an elephant?', elephant, nil)
@direction_leaf = nil
@before_leaf = nil
def ask
gets.chomp.downcase
end
def yes?(answer)
if answer == 'yes' || answer == 'y' then
return true
else
return false
end
end
# our playing session
def play( leaf )
# check if we are in very leaf node
if leaf.yes.nil? then
puts 'I win. Pretty smart, aren\'t I?'
if ask_play_again then
puts 'Think of an animal...'
play @root
end
else
puts leaf.que_name + ' (y or n)'
answer = ask
if yes?(answer) then
@before_leaf = leaf
@direction_leaf = 'yes'
play leaf.yes
else
if leaf.no.nil? then
add_information leaf
if ask_play_again then
puts 'Think of an animal...'
play @root
end
else
@direction_leaf = 'no'
@before_leaf = leaf
play leaf.no
end
end
end
end
def add_information(leaf)
puts 'You win. Help me learn from mistake before you go...'
puts 'What animal were you thinking of?'
new_animal = ask
puts 'Give me a question to distinguish ' + new_animal + ' from ' + leaf.yes.que_name + '.'
new_question = ask
puts 'For ' + new_animal + ', what is the answer to your question? (y or n)'
new_answer = ask
# created other leaf
new_upper_question = Animal.new(new_question, nil, nil)
new_animal_leaf = Animal.new(new_animal, nil, nil)
new_middle_question = Animal.new('Is it ' + new_animal + '?', new_animal_leaf, nil)
if yes?(new_answer) then
new_upper_question.no = leaf.clone
new_upper_question.yes = new_middle_question
else
new_upper_question.yes = leaf.clone
new_upper_question.no = new_middle_question
end
if @before_leaf then
if @direction_leaf == 'yes' then
@before_leaf.yes = new_upper_question
else
@before_leaf.no = new_upper_question
end
else
@root = new_upper_question
end
a = 1
end
def ask_play_again
puts 'Play again? (y or n)'
play_again = ask
yes?(play_again) ? true : false
end
# play the game
play @root
Akbar