From fefc5978a7c905b03ce4aa51824255b460e38664 Mon Sep 17 00:00:00 2001 From: Leah Hughes Date: Tue, 1 Sep 2020 07:44:58 -0700 Subject: [PATCH] methods added and tests passing --- lib/tree.rb | 185 +++++++++++++++++++++++++++++++++++++--------- test/tree_test.rb | 16 ++-- 2 files changed, 158 insertions(+), 43 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index c0d4b51..f03474c 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -1,13 +1,13 @@ class TreeNode attr_reader :key, :value attr_accessor :left, :right - - def initialize(key, val) + + def initialize(key, value) @key = key - @value = val + @value = value @left = nil @right = nil - end + end end class Tree @@ -15,50 +15,165 @@ class Tree def initialize @root = nil end - - # Time Complexity: - # Space Complexity: + + # Time Complexity: Olog(n) - only need to look at half the tree + # Space Complexity: O(1) def add(key, value) - raise NotImplementedError + new_node = TreeNode.new(key, value) + + if @root.nil? + @root = new_node + else + add_helper(@root, new_node) + end end - - # Time Complexity: - # Space Complexity: + + def add_helper(current, new_node) + return new_node if current.nil? + + if new_node.key <= current.key + current.left = add_helper(current.left, new_node) + else + current.right = add_helper(current.right, new_node) + end + + return current + end + + # Time Complexity: Olog(n) - only need to look at half the tree + # Space Complexity: O(1) def find(key) - raise NotImplementedError + return nil if @root.nil? + return @root.value if @root.key == key + + current = @root + while current != nil + if key == current.key + return current.value + elsif key < current.key + current = current.left + elsif key > current.key + current = current.right + end + end end - - # Time Complexity: - # Space Complexity: + + # Time Complexity: O(n) - n is the number of nodes in the tree + # Space Complexity: O(n) - my thought is that since we're making a list of nodes to return, we'll have that many nodes stored in the list, but since the stack doesn't ever hold something that's also already in the list, there would never be more than n nodes stored at one time..? Let me know if that's on the right track. + # left, root, right (me btwn my children) def inorder - raise NotImplementedError + return [] if @root.nil? + list = [] + stack = [] + current = @root + + # while current node exists OR the stack is not empty + while !current.nil? || !stack.empty? + + # while current node exists + while !current.nil? + # add it to the stack + stack << current + # current becomes node to its left and if it is not nil, this loop will continue + current = current.left + end + + # pop off the last node that was added + current = stack.pop + # add it to the list + list << {key: current.key, value: current.value} + # traverse to the right + current = current.right + end + + return list end - - # Time Complexity: - # Space Complexity: - def preorder - raise NotImplementedError + + # Time Complexity: O(n) - n is the number of nodes in the tree + # Space Complexity: O(n) - same assumption as inorder + # root, left, right (me before my children) + def preorder + return [] if @root.nil? + list = [] + stack = [] + current = @root + + stack.push(current) + while !stack.empty? + current = stack.pop + list << {key: current.key, value: current.value} + stack << current.right if current.right + stack << current.left if current.left + end + + return list end - - # Time Complexity: - # Space Complexity: - def postorder - raise NotImplementedError + + # Time Complexity: O(n) - n is the number of nodes in the tree + # Space Complexity: O(n) - same assumption as inorder + # left, right, root (me after my children) + def postorder + return [] if @root.nil? + + list = [] + s1 = [] + s2 = [] + current = @root + + s1 << current + while !s1.empty? + current = s1.pop + s2 << current + s1 << current.left if current.left + s1 << current.right if current.right + end + + while !s2.empty? + current = s2.pop + list << {key: current.key, value: current.value} + end + + return list end - - # Time Complexity: - # Space Complexity: + + # Time Complexity: Olog(n) in the best case (e.g. if the tree is balanced), O(n) in the worst case (the tree is unbalanced and essentially a linked list) + # Space Complexity: O(1) def height - raise NotImplementedError + return 0 if @root.nil? + return height_helper(@root) end - + + def height_helper(current) + if current.nil? + return 0 + else + return 1 + [height_helper(current.left), height_helper(current.right)].max + end + end + + # Optional Method - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) - n is number of nodes + # Space Complexity: O(n) - queue will hold at most the entire tree def bfs - raise NotImplementedError - end + return [] if @root.nil? + + queue = [] + list = [] + queue << @root + current = @root + while !queue.empty? + current = queue[0] + queue << current.left if !current.left.nil? + queue << current.right if !current.right.nil? + node_to_add = queue.shift + list << {key: node_to_add.key, value: node_to_add.value} + end + + return list + end + # Useful for printing def to_s return "#{self.inorder}" diff --git a/test/tree_test.rb b/test/tree_test.rb index d86b685..cea6e05 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -49,8 +49,8 @@ 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"}] + {:key=>5, :value=>"Peter"}, {:key=>10, :value=>"Karla"}, + {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] end end @@ -62,8 +62,8 @@ it "will return the tree in preorder" do expect(tree_with_nodes.preorder).must_equal [{:key=>5, :value=>"Peter"}, {:key=>3, :value=>"Paul"}, - {:key=>1, :value=>"Mary"}, {:key=>10, :value=>"Karla"}, - {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] + {:key=>1, :value=>"Mary"}, {:key=>10, :value=>"Karla"}, + {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] end end @@ -74,8 +74,8 @@ it "will return the tree in postorder" do expect(tree_with_nodes.postorder).must_equal [{:key=>1, :value=>"Mary"}, {:key=>3, :value=>"Paul"}, - {:key=>25, :value=>"Kari"}, {:key=>15, :value=>"Ada"}, - {:key=>10, :value=>"Karla"}, {:key=>5, :value=>"Peter"}] + {:key=>25, :value=>"Kari"}, {:key=>15, :value=>"Ada"}, + {:key=>10, :value=>"Karla"}, {:key=>5, :value=>"Peter"}] end end @@ -86,8 +86,8 @@ it "will return an array of a level-by-level output of the tree" do expect(tree_with_nodes.bfs).must_equal [{:key=>5, :value=>"Peter"}, {:key=>3, :value=>"Paul"}, - {:key=>10, :value=>"Karla"}, {:key=>1, :value=>"Mary"}, - {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] + {:key=>10, :value=>"Karla"}, {:key=>1, :value=>"Mary"}, + {:key=>15, :value=>"Ada"}, {:key=>25, :value=>"Kari"}] end end