44This implementation provides a binary search tree (BST) with basic operations
55including insertion, search, deletion, and in-order traversal. Each operation
66leverages 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
1014class 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
3033class 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
224321if __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