From f641073d1ee62b9ff308cff51bea6c280331149f Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Thu, 20 Feb 2020 16:41:58 -0800 Subject: [PATCH 1/6] add, find, inorder --- lib/tree.rb | 122 +++++++++++++++++++++++++++++++++++++++------- test/tree_test.rb | 40 ++++++++------- 2 files changed, 128 insertions(+), 34 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index c0d4b51..469ff21 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -16,45 +16,98 @@ def initialize @root = nil end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(log n) + # Space Complexity: O(n) def add(key, value) - raise NotImplementedError + @root = add_helper(@root, key, value) end - # Time Complexity: - # Space Complexity: + # def add(key, value) + # new_node = TreeNode.new(key, value) + # current = @root + # if current.nil? + # current = new_node + # else + # done = false + # until done + # if key <= current.key + # if !current.left.nil? + # current = current.left + # else + # current.left = new_node + # done = true + # end + # else + # if !current.right.nil? + # current = current.right + # else + # current.right = new_node + # done = true + # end + # end + # end + # end + # return current + # end + + # Time Complexity: O(log n) + # Space Complexity: O(n) def find(key) - raise NotImplementedError + return find_helper(@root, key) end - # Time Complexity: - # Space Complexity: + # def find(key) + # current_node = @root + # if current_node.nil? + # return nil + # else + # while true + # if current_node.key == key + # return current_node.value + # elsif current_node.key > key + # if current_node.left.nil? + # return false + # else + # current_node = current_node.left + # end + # else + # if current_node.right.nil? + # return false + # else + # current_node = current_node.right + # end + # end + # end + # end + # end + + # Time Complexity: O(n) + # Space Complexity: O(n) def inorder - raise NotImplementedError + inorder_helper(@root, []) end - # Time Complexity: - # Space Complexity: + # Time Complexity: + # Space Complexity: def preorder raise NotImplementedError end - # Time Complexity: - # Space Complexity: + # Time Complexity: + # Space Complexity: def postorder raise NotImplementedError end - # Time Complexity: - # Space Complexity: + # Time Complexity: + # Space Complexity: def height raise NotImplementedError end # Optional Method - # Time Complexity: - # Space Complexity: + # Time Complexity: + # Space Complexity: def bfs raise NotImplementedError end @@ -63,4 +116,39 @@ def bfs def to_s return "#{self.inorder}" end + + private + + def add_helper(current_node, key, value) + return TreeNode.new(key, value) if current_node.nil? + + if key <= current_node.key + current_node.left = add_helper(current_node.left, key, value) + else + current_node.right = add_helper(current_node.right, key, value) + end + + return current_node + end + + def find_helper(current_node, key) + return nil if current_node.nil? + return current_node.value if current_node.key == key + + if key <= current_node.key + return find_helper(current_node.left, key) + else + return find_helper(current_node.right, key) + end + end + + def inorder_helper(current_node, list) + return list if current_node.nil? + + inorder_helper(current_node.left, list) + list << { key: current_node.key, value: current_node.value } + inorder_helper(current_node.right, list) + + return list + end end diff --git a/test/tree_test.rb b/test/tree_test.rb index 345bf66..2f50b0f 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -13,7 +13,7 @@ tree } - describe "add and find" do + describe "add and find" do it "add & find values" do tree.add(5, "Peter") expect(tree.find(5)).must_equal "Peter" @@ -28,6 +28,12 @@ it "can't find anything when the tree is empty" do expect(tree.find(50)).must_be_nil end + + it "can't find anything when the tree doesn't have the item" do + tree.add(5, "Peter") + tree.add(15, "Ada") + expect(tree.find(50)).must_be_nil + end end describe "inorder" do @@ -36,51 +42,51 @@ 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"}, + 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 + xdescribe "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"}, + 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 - describe "postorder" do + xdescribe "postorder" do it "will give an empty array for an empty tree" do expect(tree.postorder).must_equal [] 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"}, + 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 + xdescribe "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"}, + 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 - - describe "height" do - it "will return 0 if tree is empty" do + + xdescribe "height" do + it "will return 0 if tree is empty" do expect(tree.height()).must_equal 0 end @@ -91,14 +97,14 @@ tree_with_nodes.add(65, "sam") expect(tree_with_nodes.height).must_equal 6 end - + it "will give the correct height of a binary search tree" do tree_with_nodes.add(30, "Tatiana") expect(tree_with_nodes.height).must_equal 5 end end - describe "delete" do + xdescribe "delete" do it "can delete a note in the tree" do # Arrange & Assert expect(tree_with_nodes.find(15)).must_equal "Ada" From f42465fe3c2f4a34f7a0640697db817baa1e4954 Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Thu, 20 Feb 2020 16:43:11 -0800 Subject: [PATCH 2/6] preorder --- lib/tree.rb | 12 +++++++++++- test/tree_test.rb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index 469ff21..7125038 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -90,7 +90,7 @@ def inorder # Time Complexity: # Space Complexity: def preorder - raise NotImplementedError + preorder_helper(@root, []) end # Time Complexity: @@ -151,4 +151,14 @@ def inorder_helper(current_node, list) return list end + + def preorder_helper(current_node, list) + return list if current_node.nil? + + list << { key: current_node.key, value: current_node.value } + preorder_helper(current_node.left, list) + preorder_helper(current_node.right, list) + + return list + end end diff --git a/test/tree_test.rb b/test/tree_test.rb index 2f50b0f..c81f3cc 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -49,7 +49,7 @@ end - xdescribe "preorder" do + describe "preorder" do it "will give an empty array for an empty tree" do expect(tree.preorder).must_equal [] end From b3d65e5cf3e3d1c4a2bf4e9f03498c3d4d0f9bcf Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Thu, 20 Feb 2020 16:43:59 -0800 Subject: [PATCH 3/6] postorder --- lib/tree.rb | 12 +++++++++++- test/tree_test.rb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index 7125038..1847ad3 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -96,7 +96,7 @@ def preorder # Time Complexity: # Space Complexity: def postorder - raise NotImplementedError + postorder_helper(@root, []) end # Time Complexity: @@ -161,4 +161,14 @@ def preorder_helper(current_node, list) return list end + + def postorder_helper(current_node, list) + return list if current_node.nil? + + postorder_helper(current_node.left, list) + postorder_helper(current_node.right, list) + list << { key: current_node.key, value: current_node.value } + + return list + end end diff --git a/test/tree_test.rb b/test/tree_test.rb index c81f3cc..8086556 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -61,7 +61,7 @@ end end - xdescribe "postorder" do + describe "postorder" do it "will give an empty array for an empty tree" do expect(tree.postorder).must_equal [] end From 31675cc15c96af3fc6c11018c14cdf10e025f412 Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Thu, 20 Feb 2020 16:44:26 -0800 Subject: [PATCH 4/6] added time and space complexity for preorder and postorder --- lib/tree.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index 1847ad3..79c867f 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -87,14 +87,14 @@ def inorder inorder_helper(@root, []) end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(n) def preorder preorder_helper(@root, []) end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(n) def postorder postorder_helper(@root, []) end From 0eaffee844e8a1481bcaca68c37f38bc3a787feb Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Thu, 20 Feb 2020 16:58:00 -0800 Subject: [PATCH 5/6] height --- lib/tree.rb | 19 ++++++++++++++++--- test/tree_test.rb | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/tree.rb b/lib/tree.rb index 79c867f..eeabf11 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -99,10 +99,10 @@ def postorder postorder_helper(@root, []) end - # Time Complexity: - # Space Complexity: + # Time Complexity: O(n) + # Space Complexity: O(2n) or O(n) def height - raise NotImplementedError + return height_helper(@root) end # Optional Method @@ -171,4 +171,17 @@ def postorder_helper(current_node, list) return list end + + def height_helper(current_node) + return 0 if current_node.nil? + + left_height = height_helper(current_node.left) + right_height = height_helper(current_node.right) + + if left_height >= right_height + return left_height + 1 + else + return right_height + 1 + end + end end diff --git a/test/tree_test.rb b/test/tree_test.rb index 8086556..bf382b8 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -85,7 +85,7 @@ end end - xdescribe "height" do + describe "height" do it "will return 0 if tree is empty" do expect(tree.height()).must_equal 0 end From e7ae27850f45138e1b5e04b87f029d77209e05bb Mon Sep 17 00:00:00 2001 From: Sabrina Lowney Date: Tue, 25 Feb 2020 14:14:18 -0800 Subject: [PATCH 6/6] delete --- lib/tree.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++ test/tree_test.rb | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/tree.rb b/lib/tree.rb index eeabf11..a7a62e8 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -112,6 +112,48 @@ def bfs raise NotImplementedError end + def delete(key) + parent = nil + current = @root + # find the node, keeping track of its parent + result = find_with_parent_helper(current, parent, key) + return nil if result.nil? + current = result[:current] + parent = result[:parent] + # if the found node has no children + # - if the node was parent.right, set parent.right to nil + # - if the node was parent.left, set parent.left to nil + if current.left.nil? && current.right.nil? + (parent.right == current) \ + ? parent.right = nil \ + : parent.left = nil + # else if the found node has 1 child + # - if child is .right, point parent.right to the child + elsif !current.right.nil? && current.left.nil? + (parent.right == current) \ + ? parent.right = current.right \ + : parent.left = current.right + # - if child is .left, point parent.left to the child + elsif !current.left.nil? && current.right.nil? + (parent.right == current) \ + ? parent.right = current.left \ + : parent.left = current.left + else + # else if the found node has 2 children + # - find the right child's leftmost leaf + right_child = current.right + leftmost_left = right_child.left + until leftmost_leaf.left.nil? + leftmost_leaf = leftmost_leaf.left + end + # - copy leftmost leaf to item to delete + current.value = leftmost_leaf.value + # - change right child's .left to point to leftmost leaf's .right + right_child.left = leftmost_leaf.right + # - garbage collector deletes current + end + end + # Useful for printing def to_s return "#{self.inorder}" @@ -119,6 +161,17 @@ def to_s private + def find_with_parent_helper(current_node, parent_node, key) + return nil if current_node.nil? + return {"current": current_node, "parent": parent_node} if current_node.key == key + + if key <= current_node.key + return find_with_parent_helper(current_node.left, current_node, key) + else + return find_with_parent_helper(current_node.right, current_node, key) + end + end + def add_helper(current_node, key, value) return TreeNode.new(key, value) if current_node.nil? diff --git a/test/tree_test.rb b/test/tree_test.rb index bf382b8..a33dd53 100644 --- a/test/tree_test.rb +++ b/test/tree_test.rb @@ -104,7 +104,7 @@ end end - xdescribe "delete" do + describe "delete" do it "can delete a note in the tree" do # Arrange & Assert expect(tree_with_nodes.find(15)).must_equal "Ada"