-
Notifications
You must be signed in to change notification settings - Fork 0
Bst delete #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Bst delete #11
Changes from all commits
25a38e0
97e30fc
c8b6b90
f7e5913
cb54d06
18d7877
4ba611a
cf9a522
a65f8c6
1505ae8
136cd50
621f7ff
e60cf8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,11 @@ | |
| Trees that are higher on the left than the right should return a positive value; | ||
| trees that are higher on the right than the left should return a negative value; | ||
| an ideally-balanced tree should return 0. | ||
| in_order(self): Return a generator that returns each node value from in-order traversal. | ||
| pre_order(self): Return a generator that returns each node value from pre-order traversal. | ||
| post_order(self): Return a generator that returns each node value from post_order traversal. | ||
| breadth_first(self): Return a generator returns each node value from breadth-first traversal. | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like a method is missing... |
||
| """ | ||
|
|
||
| from queue import Queue | ||
|
|
@@ -18,11 +23,12 @@ | |
| class Node(): | ||
| """Node object for the binary search tree.""" | ||
|
|
||
| def __init__(self, value, left=None, right=None): | ||
| def __init__(self, value, left=None, right=None, parent=None): | ||
| """Instantiate a node object.""" | ||
| self.value = value | ||
| self.left = left | ||
| self.right = right | ||
| self.parent = parent | ||
|
|
||
|
|
||
| class BinarySearchTree(): | ||
|
|
@@ -49,13 +55,15 @@ def insert(self, value): | |
| current_node = current_node.left | ||
| else: | ||
| current_node.left = Node(value) | ||
| current_node.left.parent = current_node | ||
| self._size += 1 | ||
| break | ||
| elif value > current_node.value: | ||
| if current_node.right: | ||
| current_node = current_node.right | ||
| else: | ||
| current_node.right = Node(value) | ||
| current_node.right.parent = current_node | ||
| self._size += 1 | ||
| break | ||
| else: | ||
|
|
@@ -126,11 +134,11 @@ def contains(self, value): | |
| def balance(self): | ||
| """Return numerical representation of how balanced the tree is.""" | ||
| if self.root.left: | ||
| depth_left = self.depth(self.root.left) | ||
| depth_left = self.depth(self.root.left) + 1 | ||
| else: | ||
| depth_left = 0 | ||
| if self.root.right: | ||
| depth_right = self.depth(self.root.right) | ||
| depth_right = self.depth(self.root.right) + 1 | ||
| else: | ||
| depth_right = 0 | ||
| balance = depth_right - depth_left | ||
|
|
@@ -191,3 +199,57 @@ def breadth_first(self): | |
| if current_node.right: | ||
| trav_list.enqueue(current_node.right) | ||
| yield current_node | ||
|
|
||
| def delete(self, value): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete breaks with empty tree. See assignment for how to handle this. In [2]: bst = BinarySearchTree()
In [3]: bst.delete(1)
---------------------------------------------------------------------------
AttributeError: 'NoneType' object has no attribute 'value' |
||
| """Get rid of a node. Or at least its connection.""" | ||
| target_node = self.search(value) | ||
| if not target_node: | ||
| return None | ||
| if not (target_node.left or target_node.right): | ||
| if target_node.value > target_node.parent.value: | ||
| target_node.parent.right = None | ||
| target_node.parent = None | ||
| self._size -= 1 | ||
| else: | ||
| target_node.parent.left = None | ||
| target_node.parent = None | ||
| self._size -= 1 | ||
| elif not (target_node.left and target_node.right): | ||
| if target_node.left: | ||
| if target_node.value < target_node.parent.value: | ||
| target_node.left.parent = target_node.parent | ||
| target_node.parent.left = target_node.left | ||
| else: | ||
| target_node.left.parent = target_node.parent | ||
| target_node.parent.right = target_node.left | ||
| self._size -= 1 | ||
| target_node.parent = None | ||
| target_node.left = None | ||
| if target_node.right: | ||
| if target_node.value < target_node.parent.value: | ||
| target_node.right.parent = target_node.parent | ||
| target_node.parent.left = target_node.right | ||
| else: | ||
| target_node.right.parent = target_node.parent | ||
| target_node.parent.right = target_node.right | ||
| self._size -= 1 | ||
| target_node.parent = None | ||
| target_node.right = None | ||
| else: | ||
| del_node = self.search(value) | ||
| current_node = del_node.right | ||
| while current_node.left: | ||
| current_node = current_node.left | ||
| replace_node = current_node | ||
| self.delete(current_node) | ||
| if del_node.parent: | ||
| replace_node.parent = del_node.parent | ||
| if replace_node.value < del_node.value: | ||
| del_node.parent.left = replace_node | ||
| else: | ||
| del_node.parent.right = replace_node | ||
| replace_node.left = del_node.left | ||
| replace_node.right = del_node.right | ||
| del_node.parent = None | ||
| del_node.left = None | ||
| del_node.right = None | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -194,6 +194,11 @@ def test_contains_true_weird_tree_root(weird_tree): | |
| assert weird_tree.contains(50) is True | ||
|
|
||
|
|
||
| def test_contains_with_nonexistent_val_gt_root(small_tree): | ||
| """Test contains returns False when value is greater than root but node nonexistent.""" | ||
| assert small_tree.contains(99) is False | ||
|
|
||
|
|
||
| def test_depth_on_small_tree(small_tree): | ||
| """Test the size on a small Tree.""" | ||
| assert small_tree.depth() == 2 | ||
|
|
@@ -213,6 +218,13 @@ def test_balance_on_weird_tree(weird_tree): | |
| """Test balance of smal tree fixture.""" | ||
| assert weird_tree.balance() == 4 | ||
|
|
||
| def test_balance_w_no_left_nodes(): | ||
| b_tree = BinarySearchTree() | ||
| b_tree.insert(17) | ||
| b_tree.insert(43) | ||
| import pdb; pdb.set_trace() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You probably shouldn't need this on github. |
||
| assert b_tree.balance() == 1 | ||
|
|
||
|
|
||
| def test_inorder_no_nodes(): | ||
| """Test in-order traversal on empty tree returns empty path.""" | ||
|
|
@@ -352,3 +364,46 @@ def test_bfs_weird_tree(weird_tree): | |
| for node in weird_tree.breadth_first(): | ||
| bfs_list.append(node.value) | ||
| assert bfs_list == [50, 44, 79, 2, 48, 80, 49, 83, 90, 100, 103, 102] | ||
|
|
||
|
|
||
| def test_delete_node_with_no_children(small_tree): | ||
| """Test calling delete on node with no children.""" | ||
| small_tree.delete(35) | ||
| assert small_tree.search(35) == None | ||
|
|
||
|
|
||
| def test_delete_node_with_no_children_annuls_parent_connection(small_tree): | ||
| """Test calling delete on node with no children kills parent's connection.""" | ||
| small_tree.delete(35) | ||
| assert small_tree.search(40).left is None | ||
| with pytest.raises(AttributeError): | ||
| assert small_tree.search(35).parent | ||
|
|
||
|
|
||
| def test_delete_node_with_no_children_annuls_own_connection(small_tree): | ||
| """Test calling delete on node with no children kills parent's connection.""" | ||
| small_tree.delete(35) | ||
| with pytest.raises(AttributeError): | ||
| assert small_tree.search(35).parent | ||
|
|
||
|
|
||
| def test_delete_node_with_one_child_reassigns_connections(small_tree): | ||
| """Test deleting a node reassigns its one child to expected new parent.""" | ||
| small_tree.delete(40) | ||
| assert small_tree.search(35).parent.value == 50 | ||
| assert small_tree.search(50).left.value == 35 | ||
|
|
||
|
|
||
| def test_delete_node_annuls_own_connections(small_tree): | ||
| """Test calling delete on node kills parent and child connections.""" | ||
| small_tree.delete(40) | ||
| with pytest.raises(AttributeError): | ||
| assert small_tree.search(40).parent is None | ||
| with pytest.raises(AttributeError): | ||
| assert small_tree.search(40).left is None | ||
|
|
||
|
|
||
| def test_delete_updates_size(small_tree): | ||
| """Test that deleting a node updates tree's size.""" | ||
| small_tree.delete(40) | ||
| assert small_tree.size() == 5 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a method is missing...