diff --git a/lib/tree.rb b/lib/tree.rb index c0d4b51..a713be4 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -2,12 +2,12 @@ class TreeNode attr_reader :key, :value attr_accessor :left, :right - def initialize(key, val) + def initialize(key, val) @key = key @value = val @left = nil @right = nil - end + end end class Tree @@ -16,47 +16,175 @@ def initialize @root = nil end - # Time Complexity: - # Space Complexity: - def add(key, value) - raise NotImplementedError + # Time Complexity: O(log n) for balanced, O(n) for unbalanced + # Space Complexity: O(log n) for balanced, O(n) for unbalanced + def add(key, value = nil) + if @root.nil? + @root = TreeNode.new(key, value) + else + add_helper(@root, key, value) + end end - # Time Complexity: - # Space Complexity: + def add_helper(current, key, value) + if current.nil? + current = TreeNode.new(key, value) + elsif key <= current.key + current.left = add_helper(current.left, key, value) + else + current.right = add_helper(current.right, key, value) + end + return current + end + +# iterative add helper + # def add_helper(current, key, value) + # added_to_tree = false + + # until added_to_tree + # if key <= current.key + # next_node = current.left + # if next_node.nil? + # new_node = TreeNode.new(key, value) + # current.left = new_node + # added_to_tree = true + # else + # current = current.left + # end + # else + # next_node = current.right + # if next_node.nil? + # new_node = TreeNode.new(key, value) + # current.right = new_node + # added_to_tree = true + # else + # current = current.right + # end + # end + # end + # end + + + + # Time Complexity: O(log n) for balanced, O(n) for unbalanced + # Space Complexity: O(log n) for balanced, O(n) for unbalanced def find(key) - raise NotImplementedError + find_helper(@root, key) + end + + def find_helper(current, key) + return nil if current.nil? + + if current.key == key + return current.value + elsif key < current.key + find_helper(current.left, key) + else + find_helper(current.right, key) + end end - # Time Complexity: - # Space Complexity: + # iterative find helper + # def find_helper(current, key) + # return nil if current.nil? + # found = false + # until found + # if current.key == key + # found = true + # return current.value + # else + # if key < current.key + # current = current.left + # else + # current = current.right + # end + # end + # return nil if current.nil? + # end + # end + + # Time Complexity: O(n) to visit all nodes + # Space Complexity: O(n) values array depends on how many nodes there are def inorder - raise NotImplementedError + values = [] + return inorder_helper(@root, values) end - # Time Complexity: - # Space Complexity: + def inorder_helper(current, values) + return values if current.nil? + + inorder_helper(current.left, values) + values.push({key: current.key, value: current.value}) + inorder_helper(current.right, values) + return values + end + + # Time Complexity: O(n) to visit all nodes + # Space Complexity: O(n) values array depends on how many nodes there are def preorder - raise NotImplementedError + values = [] + return preorder_helper(@root, values) + end + + def preorder_helper(current, values) + return values if current.nil? + + values.push({key: current.key, value: current.value}) + preorder_helper(current.left, values) + preorder_helper(current.right, values) + return values end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) to visit all nodes + # Space Complexity: O(n) values array depends on how many nodes there are def postorder - raise NotImplementedError + values = [] + return postorder_helper(@root, values) + end + + def postorder_helper(current, values) + return values if current.nil? + + postorder_helper(current.left, values) + postorder_helper(current.right, values) + values.push({key: current.key, value: current.value}) + return values end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) to visit all the nodes + # Space Complexity: O(log n) if balanced, O(n) if unbalanced def height - raise NotImplementedError + height_helper(@root) + end + + def height_helper(current) + return 0 if current.nil? + + left_height = height_helper(current.left) + right_height = height_helper(current.right) + + return left_height > right_height ? left_height + 1 : right_height + 1 end # Optional Method - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n^2) due to use of .shift + # Space Complexity: O(n) + # Solution from class def bfs - raise NotImplementedError + return [] if @root.nil? + + queue = [root] + output = [] + + until queue.empty? + node = queue.shift + output << { key: node.key, value: node.value } + + queue << node.left if node.left + queue << node.right if node.right + end + + return output end # Useful for printing @@ -64,3 +192,20 @@ def to_s return "#{self.inorder}" end end + +#### testing #### +# tree = Tree.new +# tree.add(5, "Roshni") +# tree.add(3, "Test") +# tree.add(7, "Ada") +# tree.add(34, "Grace") +# tree.add(67, "Margaret") + +# puts tree.root.value +# puts tree.root.left.value +# puts tree.root.right.value + +# puts tree.inorder +# puts tree.preorder +# puts tree.postorder +# puts tree.height \ No newline at end of file diff --git a/test/tree_test.rb b/test/tree_test.rb index dbf3447..8cba2bd 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -96,7 +96,7 @@ end it "will report the height for a balanced tree" do - expect(tree_with_nodes.height).must_equal 3 + expect(tree_with_nodes.height).must_equal 4 end it "will report the height for unbalanced trees" do