diff --git a/lib/tree.rb b/lib/tree.rb index c0d4b51..8017fad 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -2,59 +2,131 @@ 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 attr_reader :root + def initialize @root = nil end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(log n) is the best case which is a balanced tree, where n is the number of nodes. Worst case would be O(n) if each nod was more than the previous, or all less than the previous, which would just be a linked list. + # Space Complexity:O(1) only constant sized variables are used def add(key, value) - raise NotImplementedError + node = TreeNode.new(key, value) + if @root.nil? + @root = node + return + end + current = @root + until current == nil + if current.key > node.key + if current.left == nil + current.left = node + return + else + current = current.left + end + else + if current.right == nil + current.right = node + return + else + current = current.right + end + end + end end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(log n) is the best case which is a balanced tree, where n is the number of nodes. Worst case would be O(n) if each nod was more than the previous, or all less than the previous, which would just be a linked list. + # Space Complexity:O(1) only constant sized variables are used def find(key) - raise NotImplementedError + current = @root + until current == nil + if current.key > key + current = current.left + elsif current.key < key + current = current.right + else + return current.value + end + end + return nil end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) where n is the number of nodes. The inorder recurssive method is called once for each node, and the time complexity for each frame is constant. + # Space Complexity: Worst Case would be O(n^2) for a completely unbalanced tree, becuase you could have n stack frames and n arrays. Best case for a balances tree would be O(log n)^2 because you would have log n stack frames at once and log n arrays at once. def inorder - raise NotImplementedError + node = @root + return inorder_recurssive(node, []) end - # Time Complexity: - # Space Complexity: + def inorder_recurssive(curr_node, inorder_array) + return inorder_array if curr_node == nil + + inorder_array = inorder_recurssive(curr_node.left, inorder_array) + inorder_array.append({ :key => curr_node.key, :value => curr_node.value }) + inorder_array = inorder_recurssive(curr_node.right, inorder_array) + return inorder_array + end + + # Time Complexity: O(n) where n is the number of nodes. The inorder recurssive method is called once for each node, and the time complexity for each frame is constant. + # Space Complexity: Worst Case would be O(n^2) for a completely unbalanced tree, becuase you could have n stack frames and n arrays. Best case for a balances tree would be O(log n)^2 because you would have log n stack frames at once and log n arrays at once. def preorder - raise NotImplementedError + node = @root + return preorder_recurssive(node, []) end - # Time Complexity: - # Space Complexity: + def preorder_recurssive(curr_node, preorder_array) + return preorder_array if curr_node == nil + preorder_array.append({ :key => curr_node.key, :value => curr_node.value }) + preorder_array = preorder_recurssive(curr_node.left, preorder_array) + preorder_array = preorder_recurssive(curr_node.right, preorder_array) + end + + # Time Complexity: O(n) where n is the number of nodes. The inorder recurssive method is called once for each node, and the time complexity for each frame is constant. + # Space Complexity: Worst Case would be O(n^2) for a completely unbalanced tree, becuase you could have n stack frames and n arrays. Best case for a balances tree would be O(log n)^2 because you would have log n stack frames at once and log n arrays at once. def postorder - raise NotImplementedError + node = @root + return postorder_recurssive(node, []) end - # Time Complexity: - # Space Complexity: + def postorder_recurssive(curr_node, postorder_array) + return postorder_array if curr_node == nil + postorder_array = postorder_recurssive(curr_node.left, postorder_array) + postorder_array = postorder_recurssive(curr_node.right, postorder_array) + postorder_array.append({ :key => curr_node.key, :value => curr_node.value }) + end + + # Time Complexity: O(n) where n is the number of nodes. The inorder recurssive method is called once for each node, and the time complexity for each frame is constant. + # Space Complexity: O(n) is the worst case because you would have n stack frames, where n is the number of nodes. Best case on a balamced tree would be O(log n) because you would have at most the height number of stack frames, which is log n. def height - raise NotImplementedError + return 0 if @root == nil + node = @root + return height_recurssive(node, 1, 1) + end + + def height_recurssive(curr_node, curr_height, max_height) + return max_height if curr_node == nil + + max_height = curr_height if curr_height > max_height + max_height = height_recurssive(curr_node.left, curr_height += 1, max_height) + curr_height -= 1 + max_height = height_recurssive(curr_node.right, curr_height += 1, max_height) + + return max_height end # Optional Method - # Time Complexity: - # Space Complexity: + # Time Complexity: + # Space Complexity: def bfs raise NotImplementedError end diff --git a/test/tree_test.rb b/test/tree_test.rb index 8811f14..aebe90b 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -1,10 +1,9 @@ -require_relative 'test_helper' - +require_relative "test_helper" Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new describe Tree do - let (:tree) {Tree.new} + let (:tree) { Tree.new } let (:tree_with_nodes) { tree.add(5, "Peter") @@ -37,23 +36,21 @@ 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"}] + 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" }] end end - describe "preorder" do it "will give an empty array for an empty tree" do expect(tree.preorder).must_equal [] end 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"}] + 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" }] end end @@ -63,21 +60,33 @@ end 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"}] + 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" }] end end - describe "breadth first search" do - it "will give an empty array for an empty tree" do - expect(tree.bfs).must_equal [] + describe "height" do + it "will find the height of a tree" do + tree_with_nodes.add(9, "Jo") + tree_with_nodes.add(14, "Jane") + tree_with_nodes.add(4, "Jil") + expect(tree_with_nodes.height()).must_equal 4 end - - 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"}] + it "will return 0 for an empty tree" do + expect(tree.height()).must_equal 0 end end -end \ No newline at end of file + + # describe "breadth first search" do + # it "will give an empty array for an empty tree" do + # expect(tree.bfs).must_equal [] + # end + + # 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" }] + # end + # end +end