Skip to content

Commit 0d5e266

Browse files
Binary search tree
1 parent 286c4c5 commit 0d5e266

1 file changed

Lines changed: 160 additions & 90 deletions

File tree

tree/binary_search_tree.py

Lines changed: 160 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
This implementation provides a binary search tree (BST) with basic operations
55
including insertion, search, deletion, and in-order traversal. Each operation
66
leverages recursive helper functions.
7-
"""
87
8+
Binary Search Tree Implementation with Doctest Examples
9+
10+
To run the doctests:
11+
python -m doctest -v binary_search_tree.py
12+
"""
913

1014
class BSTNode:
1115
"""
12-
A node in a binary search tree.
16+
A node in the binary search tree.
1317
1418
Attributes
1519
----------
@@ -20,31 +24,18 @@ class BSTNode:
2024
right : BSTNode or None
2125
The right child node.
2226
"""
23-
24-
def __init__(self, key: int):
27+
def __init__(self, key: int) -> None:
2528
self.key = key
2629
self.left = None
2730
self.right = None
2831

2932

3033
class BinarySearchTree:
3134
"""
32-
Binary Search Tree (BST) class that supports basic operations such as
35+
Binary Search Tree (BST) class that supports operations such as
3336
insertion, search, deletion, and in-order traversal.
34-
35-
Methods
36-
-------
37-
insert(key: int) -> None
38-
Inserts a new key into the BST.
39-
search(key: int) -> BSTNode or None
40-
Searches for a key in the BST and returns the node if found.
41-
delete(key: int) -> None
42-
Deletes a key from the BST if it exists.
43-
inorder_traversal() -> list
44-
Returns a list of keys representing the in-order traversal of the BST.
4537
"""
46-
47-
def __init__(self):
38+
def __init__(self) -> None:
4839
"""
4940
Initializes an empty Binary Search Tree.
5041
"""
@@ -58,6 +49,15 @@ def insert(self, key: int) -> None:
5849
----------
5950
key : int
6051
The key to be inserted into the BST.
52+
53+
Examples
54+
--------
55+
>>> bst = BinarySearchTree()
56+
>>> bst.insert(10)
57+
>>> bst.insert(5)
58+
>>> bst.insert(15)
59+
>>> bst.inorder_traversal()
60+
[5, 10, 15]
6161
"""
6262
if self.root is None:
6363
self.root = BSTNode(key)
@@ -66,14 +66,23 @@ def insert(self, key: int) -> None:
6666

6767
def _insert_recursive(self, node: BSTNode, key: int) -> None:
6868
"""
69-
Recursively inserts the new key into the subtree rooted at the given node.
69+
Recursively inserts a new key into the subtree rooted at the given node.
7070
7171
Parameters
7272
----------
7373
node : BSTNode
7474
The current node in the BST.
7575
key : int
76-
The key to be inserted.
76+
The key to insert.
77+
78+
Examples
79+
--------
80+
>>> bst = BinarySearchTree()
81+
>>> bst.root = BSTNode(10)
82+
>>> bst._insert_recursive(bst.root, 5)
83+
>>> bst._insert_recursive(bst.root, 15)
84+
>>> bst.inorder_traversal()
85+
[5, 10, 15]
7786
"""
7887
if key < node.key:
7988
if node.left is None:
@@ -86,9 +95,69 @@ def _insert_recursive(self, node: BSTNode, key: int) -> None:
8695
else:
8796
self._insert_recursive(node.right, key)
8897

89-
def search(self, key: int) -> BSTNode:
98+
def inorder_traversal(self) -> list:
9099
"""
91-
Searches for a key in the BST.
100+
Performs an in-order traversal of the BST and returns the keys in sorted order.
101+
102+
Returns
103+
-------
104+
list
105+
A list of keys in increasing order.
106+
107+
Examples
108+
--------
109+
>>> bst = BinarySearchTree()
110+
>>> bst.inorder_traversal() # For an empty BST.
111+
[]
112+
>>> bst.insert(10)
113+
>>> bst.insert(5)
114+
>>> bst.insert(15)
115+
>>> bst.inorder_traversal()
116+
[5, 10, 15]
117+
>>> bst.insert(7)
118+
>>> bst.inorder_traversal()
119+
[5, 7, 10, 15]
120+
"""
121+
result = []
122+
self._inorder_recursive(self.root, result)
123+
return result
124+
125+
def _inorder_recursive(self, node: BSTNode, result: list) -> None:
126+
"""
127+
Helper function for recursively performing in-order traversal by accumulating the keys.
128+
129+
Parameters
130+
----------
131+
node : BSTNode or None
132+
The current node being visited.
133+
result : list
134+
The list accumulating the keys.
135+
136+
Examples
137+
--------
138+
>>> bst = BinarySearchTree()
139+
>>> # Manually build a simple BST.
140+
>>> bst.root = BSTNode(20)
141+
>>> bst.root.left = BSTNode(10)
142+
>>> bst.root.right = BSTNode(30)
143+
>>> result = []
144+
>>> bst._inorder_recursive(bst.root, result)
145+
>>> result
146+
[10, 20, 30]
147+
>>> # If the subtree is empty, the result remains unchanged.
148+
>>> result = [1, 2, 3]
149+
>>> bst._inorder_recursive(None, result)
150+
>>> result
151+
[1, 2, 3]
152+
"""
153+
if node is not None:
154+
self._inorder_recursive(node.left, result)
155+
result.append(node.key)
156+
self._inorder_recursive(node.right, result)
157+
158+
def search(self, key: int):
159+
"""
160+
Searches for a given key in the BST using a recursive approach.
92161
93162
Parameters
94163
----------
@@ -98,13 +167,25 @@ def search(self, key: int) -> BSTNode:
98167
Returns
99168
-------
100169
BSTNode or None
101-
The node containing the key if found, or None otherwise.
170+
The node containing the key if found; otherwise, None.
171+
172+
Examples
173+
--------
174+
>>> bst = BinarySearchTree()
175+
>>> bst.insert(10)
176+
>>> bst.insert(5)
177+
>>> bst.insert(15)
178+
>>> node = bst.search(5)
179+
>>> node.key
180+
5
181+
>>> bst.search(20) is None
182+
True
102183
"""
103184
return self._search_recursive(self.root, key)
104185

105-
def _search_recursive(self, node: BSTNode, key: int) -> BSTNode:
186+
def _search_recursive(self, node: BSTNode, key: int):
106187
"""
107-
Recursively searches for a key in the tree.
188+
Helper function to recursively search for a key in the BST.
108189
109190
Parameters
110191
----------
@@ -116,7 +197,17 @@ def _search_recursive(self, node: BSTNode, key: int) -> BSTNode:
116197
Returns
117198
-------
118199
BSTNode or None
119-
The node containing the key if found, otherwise None.
200+
The node containing the key if found; otherwise, None.
201+
202+
Examples
203+
--------
204+
>>> bst = BinarySearchTree()
205+
>>> bst.root = BSTNode(10)
206+
>>> bst.root.left = BSTNode(5)
207+
>>> bst._search_recursive(bst.root, 5).key
208+
5
209+
>>> bst._search_recursive(bst.root, 20) is None
210+
True
120211
"""
121212
if node is None or node.key == key:
122213
return node
@@ -127,18 +218,32 @@ def _search_recursive(self, node: BSTNode, key: int) -> BSTNode:
127218

128219
def delete(self, key: int) -> None:
129220
"""
130-
Deletes a key from the BST if it exists.
221+
Deletes the node with the specified key from the BST if it exists.
131222
132223
Parameters
133224
----------
134225
key : int
135226
The key to be deleted.
227+
228+
Examples
229+
--------
230+
>>> bst = BinarySearchTree()
231+
>>> for key in [10, 5, 15, 2, 7]:
232+
... bst.insert(key)
233+
>>> bst.inorder_traversal()
234+
[2, 5, 7, 10, 15]
235+
>>> bst.delete(5)
236+
>>> bst.inorder_traversal()
237+
[2, 7, 10, 15]
238+
>>> bst.delete(20) # Deleting a non-existent key leaves the tree unchanged.
239+
>>> bst.inorder_traversal()
240+
[2, 7, 10, 15]
136241
"""
137242
self.root = self._delete_recursive(self.root, key)
138243

139-
def _delete_recursive(self, node: BSTNode, key: int) -> BSTNode:
244+
def _delete_recursive(self, node: BSTNode, key: int):
140245
"""
141-
Recursively deletes a key from the subtree rooted at the given node.
246+
Recursively deletes the node with the specified key from the subtree.
142247
143248
Parameters
144249
----------
@@ -151,6 +256,15 @@ def _delete_recursive(self, node: BSTNode, key: int) -> BSTNode:
151256
-------
152257
BSTNode or None
153258
The new root of the subtree after deletion.
259+
260+
Examples
261+
--------
262+
>>> bst = BinarySearchTree()
263+
>>> bst.root = BSTNode(10)
264+
>>> bst.root.left = BSTNode(5)
265+
>>> bst.root.right = BSTNode(15)
266+
>>> bst._delete_recursive(bst.root, 5).key
267+
10
154268
"""
155269
if node is None:
156270
return node
@@ -160,13 +274,13 @@ def _delete_recursive(self, node: BSTNode, key: int) -> BSTNode:
160274
elif key > node.key:
161275
node.right = self._delete_recursive(node.right, key)
162276
else:
163-
# Node found; handle deletions for nodes with 0 or 1 child.
277+
# Node with only one child or no child.
164278
if node.left is None:
165279
return node.right
166280
elif node.right is None:
167281
return node.left
168282

169-
# Node with two children: get the inorder successor (smallest in the right subtree)
283+
# Node with two children: Get the in-order successor.
170284
temp = self._find_min(node.right)
171285
node.key = temp.key
172286
node.right = self._delete_recursive(node.right, temp.key)
@@ -184,70 +298,26 @@ def _find_min(self, node: BSTNode) -> BSTNode:
184298
Returns
185299
-------
186300
BSTNode
187-
The node with the smallest key in the subtree.
301+
The node with the smallest key.
302+
303+
Examples
304+
--------
305+
>>> bst = BinarySearchTree()
306+
>>> bst.root = BSTNode(10)
307+
>>> bst.root.left = BSTNode(5)
308+
>>> bst.root.right = BSTNode(15)
309+
>>> bst._find_min(bst.root).key
310+
5
311+
>>> bst.root.left.left = BSTNode(2)
312+
>>> bst._find_min(bst.root).key
313+
2
188314
"""
189315
current = node
190316
while current.left is not None:
191317
current = current.left
192318
return current
193319

194-
def inorder_traversal(self) -> list:
195-
"""
196-
Performs an in-order traversal of the BST.
197-
198-
Returns
199-
-------
200-
list
201-
A list of keys in sorted order.
202-
"""
203-
result = []
204-
self._inorder_recursive(self.root, result)
205-
return result
206-
207-
def _inorder_recursive(self, node: BSTNode, result: list) -> None:
208-
"""
209-
Recursively performs an in-order traversal of the BST and appends keys to the result list.
210-
211-
Parameters
212-
----------
213-
node : BSTNode or None
214-
The current node in the BST.
215-
result : list
216-
The list that accumulates the keys.
217-
"""
218-
if node is not None:
219-
self._inorder_recursive(node.left, result)
220-
result.append(node.key)
221-
self._inorder_recursive(node.right, result)
222-
223320

224321
if __name__ == "__main__":
225-
"""
226-
Testing the Binary Search Tree (BST) implementation.
227-
228-
Example:
229-
--------
230-
1. Insert nodes with keys: [50, 30, 70, 20, 40, 60, 80]
231-
2. Display the in-order traversal after insertion.
232-
3. Search for a key (e.g., 40).
233-
4. Delete a key (e.g., 30) and display the new in-order traversal.
234-
"""
235-
bst = BinarySearchTree()
236-
237-
# Insert nodes into the BST
238-
nodes_to_insert = [50, 30, 70, 20, 40, 60, 80]
239-
for key in nodes_to_insert:
240-
bst.insert(key)
241-
print("In-order traversal after insertion:", bst.inorder_traversal())
242-
243-
# Search for a key in the BST
244-
search_key = 40
245-
result = bst.search(search_key)
246-
if result:
247-
print(f"Node with key {search_key} found.")
248-
else:
249-
print(f"Node with key {search_key} not found.")
250-
251-
# Delete a node from the BST
252-
bst.delete(30)
253-
print("In-order traversal after deleting 30:", bst.inorder_traversal())
322+
import doctest
323+
doctest.testmod()

0 commit comments

Comments
 (0)