diff --git a/lib/tree.rb b/lib/tree.rb index c0d4b51..aadb3b2 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -16,47 +16,163 @@ def initialize @root = nil end - # Time Complexity: - # Space Complexity: - def add(key, value) - raise NotImplementedError + # Time Complexity: O(logn) + # Space Complexity: O(logn) + def add(key, value = nil) + unless root + @root = TreeNode.new(key, value) + else + add_helper(@root, key, value) + end end - # Time Complexity: - # Space Complexity: + def add_helper(current, key, value) + return TreeNode.new(key, value) unless current + + if key < current.key + current.left = add_helper(current.left, key, value) + else + current.right = add_helper(current.right, key, value) + end + + # still working through why this needed/what would happen with no return + return current + # i think needed bc you assign current.left/right + # to the return of add_helper + # this assignment is needed because you will need + # to connect the new node to a leaf node + # (set that leaf node's .left/.right) + # so for a given current node, you need to know what + # it should be linked to (ie it's .left/right) + # which means that on the next iteration, just return + # that current's value to fill this in later + # ^ bad explanation - but if current = 97, and current.left is 91 + # you need to return 91 on the next recursive call (when current is 91) + # so that way when you work back up the callstack, you'll know that when + # current is 97, set 97.left to be 91 (bc 91 is returned from helper(97.left)) + + # if you didn't return current + # just return -> going back up the callstack would be setting current.left/right to nil + # no return -> i think bc of implicit returns in ruby, it would just carry the + # assignment from the base case all the way up + # so like in find for ex, once you find it, it just carries that val all the way up + # when you're assigning, it takes the old leaf nodes assignment of .left/.right and just carries + # that all the way up + # this is why when i was playing around with it (without a return), in the case of adding a 3rd(+) node, + # the code would just set what root.left/right's left/right to be the node i was adding + # it basically takes that assignment from the base case and carries it all the way up + # see ex on line 186, when you dont have a return after an if block, the method just returns what the if block returned (when you print it) + + end + + # Time Complexity: O(logn) + # Space Complexity: O(logn) def find(key) - raise NotImplementedError + return find_helper(@root, key) + end + + def find_helper(current, key) + return current unless current + return current.value if key == current.key + + if current.key < key + find_helper(current.right, key) + else + find_helper(current.left, key) + end + + # Q: why isnt a return needed here? + # A: i think bc it just carries that return current all the way back up + # implicit returns in ruby end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(n) def inorder - raise NotImplementedError + tree_in_order = [] + inorder_helper(tree_in_order, @root) end - # Time Complexity: - # Space Complexity: + def inorder_helper(tree, current) + return tree unless current + + inorder_helper(tree, current.left) + tree.push({:key=>current.key, :value=>current.value}) + inorder_helper(tree, current.right) + + # return tree + end + + # Time Complexity: O(n) + # Space Complexity: O(n) def preorder - raise NotImplementedError + tree_pre_order = [] + return preorder_helper(@root, tree_pre_order) + end + + def preorder_helper(current, tree) + return tree unless current + + tree.push({:key=>current.key, :value=>current.value}) + preorder_helper(current.left, tree) + preorder_helper(current.right, tree) + + return tree end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(n) def postorder - raise NotImplementedError + tree_post_order = [] + return postorder_helper(@root, tree_post_order) end - # Time Complexity: - # Space Complexity: + def postorder_helper(current, tree) + return tree unless current + + postorder_helper(current.left, tree) + postorder_helper(current.right, tree) + tree.push({:key=>current.key, :value=>current.value}) + + return tree + end + + # Time Complexity: O(n) + # Space Complexity: O(n) def height - raise NotImplementedError + return height_helper(@root) + end + + def height_helper(current) + return 0 unless current + + left_height = height_helper(current.left) + right_height = height_helper(current.right) + + return left_height < right_height ? right_height + 1 : left_height + 1 end # Optional Method - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n*m) + # Space Complexity: O(n) def bfs - raise NotImplementedError + q = [] + tree_bfs = [] + return tree_bfs unless @root + + q.push(@root) + + until q.empty? + current = q.shift + + tree_bfs.push({:key=>current.key, :value=>current.value}) + + q.push(current.left) if current.left + q.push(current.right) if current.right + end + + return tree_bfs + end # Useful for printing @@ -64,3 +180,35 @@ def to_s return "#{self.inorder}" end end + + +def test(x, y) + if x == 1 + x = 3 + # p (y) + else + x = 4 + # p ("no") + end + # return +end + +# p test(1, 2) + + +tree = Tree.new() +tree.add(5, "5") +tree.add(3, "3") +tree.add(1, "1") +# 5 +# 3 +# 1 +p tree.inorder + +tree = Tree.new() +tree.add(1, "1") +tree.add(3, "3") +tree.add(5, "5") + # 1 + # 3 5 +p tree.inorder \ No newline at end of file diff --git a/test/tree_test.rb b/test/tree_test.rb index dbf3447..339c38b 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -37,7 +37,6 @@ end it "will return the tree in order" do - expect(tree_with_nodes.inorder).must_equal [{:key=>1, :value=>"Mary"}, {:key=>3, :value=>"Paul"}, {:key=>5, :value=>"Peter"}, {:key=>10, :value=>"Karla"}, {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] @@ -95,8 +94,8 @@ expect(my_tree.height).must_equal 1 end - it "will report the height for a balanced tree" do - expect(tree_with_nodes.height).must_equal 3 + it "will report the height for a tree with height 4 on right and 3 on left" do + expect(tree_with_nodes.height).must_equal 4 end it "will report the height for unbalanced trees" do