Skip to content

Commit 2ec36f3

Browse files
authored
Merge pull request #91 from UBC-MDS/fix-delete_search_enhancement
Fix delete search enhancement, also added time and space complexity in readme
2 parents 6e332de + 1f44da7 commit 2ec36f3

File tree

4 files changed

+106
-23
lines changed

4 files changed

+106
-23
lines changed

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
- Keys in the right subtree of a node are larger than the node’s key.
1717
- Duplicate keys are not allowed.
1818

19+
Time Complexity:
20+
Search, Insert, Delete:
21+
- Average Case: O(log n) => This occurs when the BST is balanced.
22+
- Worst Case: O(n) => This occurs when the BST is skewed.
23+
24+
Space Complexity:
25+
- Space for the BST: O(n).
26+
- Recursive Operations: O(h), where h is the height of the tree.
27+
1928
**Methods**
2029
- **`insert(key)`**:
2130
- Inserts a specified key into the Binary Search Tree (BST) while maintaining BST properties.

src/datastructpy/non_linear/trees/binary_search_tree.py

+32-4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ def search(self, key):
9494
- The Node object containing the specified key if found.
9595
- None if the key does not exist or the tree is empty.
9696
97+
Raises
98+
------
99+
TypeError
100+
If the key is not an integer or is None.
101+
97102
Examples
98103
--------
99104
>>> bst = BinarySearchTree()
@@ -105,6 +110,11 @@ def search(self, key):
105110
>>> bst.search(20) is None
106111
True
107112
"""
113+
if key is None:
114+
raise TypeError("None values are not allowed in the BST.")
115+
if not isinstance(key, int):
116+
raise TypeError("Only integers are allowed in the BST.")
117+
108118
current = self.root
109119
while current is not None:
110120
if key == current.key:
@@ -128,19 +138,34 @@ def delete(self, key):
128138
key : int
129139
The value to delete from the BST.
130140
141+
Returns
142+
-------
143+
bool
144+
- True if the key was found and deleted.
145+
- False if the key was not found.
146+
147+
Raises
148+
------
149+
TypeError
150+
If the key is not an integer or is None.
151+
131152
Examples
132153
--------
133154
>>> bst = BinarySearchTree()
134155
>>> bst.insert(10)
135156
>>> bst.insert(5)
136157
>>> bst.insert(15)
137158
>>> bst.delete(10)
138-
>>> bst.root.key
139-
15
159+
True
160+
>>> bst.delete(20)
161+
False
140162
"""
163+
if key is None:
164+
raise TypeError("None values are not allowed in the BST.")
165+
if not isinstance(key, int):
166+
raise TypeError("Only integers are allowed in the BST.")
167+
141168
def _delete(node, key):
142-
if node is None:
143-
return None
144169
if key < node.key:
145170
node.left = _delete(node.left, key)
146171
elif key > node.key:
@@ -157,7 +182,10 @@ def _delete(node, key):
157182
node.right = _delete(node.right, min_larger_node.key)
158183
return node
159184

185+
if self.search(key) is None:
186+
return False
160187
self.root = _delete(self.root, key)
188+
return True
161189

162190
@staticmethod
163191
def list_to_tree(elements):

tests/non-linear/trees/binary_search_tree/test_delete.py

+56-15
Original file line numberDiff line numberDiff line change
@@ -18,43 +18,84 @@ def bst():
1818
def test_delete_empty_tree():
1919
"""
2020
Tests the delete operation on an empty tree.
21-
Deleting a key from an empty BST should not cause any errors.
21+
Deleting a key from an empty BST should return False.
2222
"""
2323
bst = BinarySearchTree()
24-
bst.delete(10)
25-
assert bst.root is None, "Deleting from an empty tree should do nothing."
24+
assert not bst.delete(10), "Deleting from an empty tree should return False."
2625

2726
def test_delete_leaf_node(bst):
2827
"""
2928
Tests the deletion of a leaf node (node with no children).
3029
"""
31-
bst.delete(5)
32-
assert bst.search(5) is None, "Leaf node 5 should be deleted."
30+
assert bst.delete(5), "Leaf node 5 should be successfully deleted."
31+
assert bst.search(5) is None, "Leaf node 5 should no longer be in the tree."
32+
33+
def test_delete_non_existent_key(bst):
34+
"""
35+
Tests deleting a key that does not exist in the BST.
36+
Should return False without modifying the tree.
37+
"""
38+
assert not bst.delete(100), "Deleting a non-existent key should return False."
39+
40+
def test_delete_non_integer(bst):
41+
"""
42+
Tests deleting a key that isn't an integer (string).
43+
Should raise a TypeError.
44+
"""
45+
with pytest.raises(TypeError):
46+
bst.delete("100")
47+
48+
def test_delete_none_key(bst):
49+
"""
50+
Tests deleting a None key.
51+
Should raise a TypeError.
52+
"""
53+
with pytest.raises(TypeError):
54+
bst.delete(None)
55+
56+
def test_delete_none_node(bst):
57+
"""
58+
Tests deleting a key that does not exist in the BST.
59+
Should return False without modifying the tree.
60+
"""
61+
bst = BinarySearchTree()
62+
assert not bst.delete(100), "Deleting a non-existent key should return False."
63+
64+
def test_delete_node_with_only_left_child():
65+
"""
66+
Tests deleting a node that has only a left child.
67+
Ensures it reaches the `elif node.right is None: return node.left` condition.
68+
"""
69+
bst = BinarySearchTree()
70+
bst.insert(10)
71+
bst.insert(5) # Left child only
72+
assert bst.delete(10), "Node 10 should be successfully deleted."
73+
assert bst.root.key == 5, "Node 5 should replace node 10."
3374

3475
def test_delete_traverse_right_subtree(bst):
3576
"""
3677
Tests the deletion of a node located in the right subtree.
3778
"""
38-
bst.delete(30)
39-
assert bst.search(30) is None, "Node 30 should be deleted."
79+
assert bst.delete(30), "Node 30 should be successfully deleted."
80+
assert bst.search(30) is None, "Node 30 should no longer be in the tree."
4081
assert bst.root.right.key == 35, "Node 35 should replace node 30 in the right subtree."
4182

4283
def test_delete_node_with_one_child(bst):
4384
"""
4485
Tests the deletion of a node with only one child.
4586
The child node should replace the deleted node.
4687
"""
47-
bst.delete(10)
48-
assert bst.search(10) is None, "Node 10 should be deleted."
88+
assert bst.delete(10), "Node 10 should be successfully deleted."
89+
assert bst.search(10) is None, "Node 10 should no longer be in the tree."
4990
assert bst.root.left.key == 15, "Node 15 should replace node 10."
5091

5192
def test_delete_node_with_two_children(bst):
5293
"""
5394
Tests the deletion of a node that has two children.
5495
The node should be replaced by its in-order successor.
5596
"""
56-
bst.delete(20)
57-
assert bst.search(20) is None, "Node 20 should be deleted."
97+
assert bst.delete(20), "Node 20 should be successfully deleted."
98+
assert bst.search(20) is None, "Node 20 should no longer be in the tree."
5899
assert bst.root.key == 25, "Root should now be replaced by in-order successor 25."
59100

60101
def test_delete_root_node():
@@ -64,14 +105,14 @@ def test_delete_root_node():
64105
"""
65106
bst = BinarySearchTree()
66107
bst.insert(10)
67-
bst.delete(10)
68-
assert bst.search(10) is None, "Root node 10 should be deleted."
108+
assert bst.delete(10), "Root node 10 should be successfully deleted."
109+
assert bst.search(10) is None, "Root node 10 should no longer be in the tree."
69110

70111
def test_delete_complex_tree(bst):
71112
"""
72113
Tests the deletion of a node in a complex tree structure.
73114
Ensures the BST maintains correct structure after deletion.
74115
"""
75-
bst.delete(20) # Deleting root with two children
76-
assert bst.search(20) is None, "Root 20 should be deleted."
116+
assert bst.delete(20), "Root 20 should be successfully deleted."
117+
assert bst.search(20) is None, "Root 20 should no longer be in the tree."
77118
assert bst.root.key == 25, "Root should now be replaced by in-order successor 25."

tests/non-linear/trees/binary_search_tree/test_search.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,14 @@ def test_search_empty_tree():
4343
empty_bst = BinarySearchTree()
4444
assert empty_bst.search(10) is None # Should return None
4545

46-
def test_search_invalid_algorithm(bst):
46+
def test_search_invalid_key():
4747
"""
48-
Tests if search() handles invalid algorithm names properly.
48+
Tests if search() raises TypeError for invalid key types.
4949
"""
50-
with pytest.raises(TypeError): # Since 'algorithm' is removed, this should raise a TypeError
51-
bst.search(10, algorithm='invalid_algorithm')
50+
bst = BinarySearchTree.list_to_tree([10, 5, 15])
51+
with pytest.raises(TypeError):
52+
bst.search(None)
53+
with pytest.raises(TypeError):
54+
bst.search("string")
55+
with pytest.raises(TypeError):
56+
bst.search(10.5)

0 commit comments

Comments
 (0)