Skip to content

Commit 0345350

Browse files
authored
Update binary_search_tree.py
1 parent 92b7060 commit 0345350

File tree

1 file changed

+33
-291
lines changed

1 file changed

+33
-291
lines changed
Lines changed: 33 additions & 291 deletions
Original file line numberDiff line numberDiff line change
@@ -1,184 +1,46 @@
1-
r"""
2-
A binary search Tree
3-
4-
Example
5-
8
6-
/ \
7-
3 10
8-
/ \ \
9-
1 6 14
10-
/ \ /
11-
4 7 13
12-
13-
>>> t = BinarySearchTree().insert(8, 3, 6, 1, 10, 14, 13, 4, 7)
14-
>>> print(" ".join(repr(i.value) for i in t.traversal_tree()))
15-
8 3 1 6 4 7 10 14 13
16-
17-
>>> tuple(i.value for i in t.traversal_tree(inorder))
18-
(1, 3, 4, 6, 7, 8, 10, 13, 14)
19-
>>> tuple(t)
20-
(1, 3, 4, 6, 7, 8, 10, 13, 14)
21-
>>> t.find_kth_smallest(3, t.root)
22-
4
23-
>>> tuple(t)[3-1]
24-
4
25-
26-
>>> print(" ".join(repr(i.value) for i in t.traversal_tree(postorder)))
27-
1 4 7 6 3 13 14 10 8
28-
>>> t.remove(20)
29-
Traceback (most recent call last):
30-
...
31-
ValueError: Value 20 not found
32-
>>> BinarySearchTree().search(6)
33-
Traceback (most recent call last):
34-
...
35-
IndexError: Warning: Tree is empty! please use another.
36-
37-
Other example:
38-
39-
>>> testlist = (8, 3, 6, 1, 10, 14, 13, 4, 7)
40-
>>> t = BinarySearchTree()
41-
>>> for i in testlist:
42-
... t.insert(i) # doctest: +ELLIPSIS
43-
BinarySearchTree(root=8)
44-
BinarySearchTree(root={'8': (3, None)})
45-
BinarySearchTree(root={'8': ({'3': (None, 6)}, None)})
46-
BinarySearchTree(root={'8': ({'3': (1, 6)}, None)})
47-
BinarySearchTree(root={'8': ({'3': (1, 6)}, 10)})
48-
BinarySearchTree(root={'8': ({'3': (1, 6)}, {'10': (None, 14)})})
49-
BinarySearchTree(root={'8': ({'3': (1, 6)}, {'10': (None, {'14': (13, None)})})})
50-
BinarySearchTree(root={'8': ({'3': (1, {'6': (4, None)})}, {'10': (None, {'14': ...
51-
BinarySearchTree(root={'8': ({'3': (1, {'6': (4, 7)})}, {'10': (None, {'14': (13, ...
52-
53-
Prints all the elements of the list in order traversal
54-
>>> print(t)
55-
{'8': ({'3': (1, {'6': (4, 7)})}, {'10': (None, {'14': (13, None)})})}
56-
57-
Test existence
58-
>>> t.search(6) is not None
59-
True
60-
>>> 6 in t
61-
True
62-
>>> t.search(-1) is not None
63-
False
64-
>>> -1 in t
65-
False
66-
67-
>>> t.search(6).is_right
68-
True
69-
>>> t.search(1).is_right
70-
False
71-
72-
>>> t.get_max().value
73-
14
74-
>>> max(t)
75-
14
76-
>>> t.get_min().value
77-
1
78-
>>> min(t)
79-
1
80-
>>> t.empty()
81-
False
82-
>>> not t
83-
False
84-
>>> for i in testlist:
85-
... t.remove(i)
86-
>>> t.empty()
87-
True
88-
>>> not t
89-
True
90-
"""
911
from __future__ import annotations
92-
from pprint import pformat # Moved to top-level
2+
from pprint import pformat
933
from collections.abc import Iterable, Iterator
944
from dataclasses import dataclass
955
from typing import Any, Self
966

97-
987
@dataclass
998
class Node:
1009
value: int
10110
left: Node | None = None
10211
right: Node | None = None
103-
parent: Node | None = None # Added in order to delete a node easier
104-
105-
def __iter__(self) -> Iterator[int]:
106-
"""
107-
>>> list(Node(0))
108-
[0]
109-
>>> list(Node(0, Node(-1), Node(1), None))
110-
[-1, 0, 1]
111-
"""
112-
yield from self.left or []
113-
yield self.value
114-
yield from self.right or []
12+
parent: Node | None = None
11513

11614
def __repr__(self) -> str:
11715
if self.left is None and self.right is None:
11816
return str(self.value)
11917
return pformat({f"{self.value}": (self.left, self.right)}, indent=1)
12018

121-
@property
122-
def is_right(self) -> bool:
123-
return bool(self.parent and self is self.parent.right)
124-
125-
12619
@dataclass
12720
class BinarySearchTree:
12821
root: Node | None = None
12922

130-
def __bool__(self) -> bool:
131-
return bool(self.root)
132-
133-
def __iter__(self) -> Iterator[int]:
134-
yield from self.root or []
135-
136-
def __str__(self) -> str:
137-
"""
138-
Return a string of all the Nodes using in order traversal
139-
"""
140-
return str(self.root)
141-
14223
def __reassign_nodes(self, node: Node, new_children: Node | None) -> None:
143-
if new_children is not None: # reset its kids
24+
if new_children is not None:
14425
new_children.parent = node.parent
145-
if node.parent is not None: # reset its parent
146-
if node.is_right: # If it is the right child
26+
if node.parent is not None:
27+
if node.is_right:
14728
node.parent.right = new_children
14829
else:
14930
node.parent.left = new_children
15031
else:
15132
self.root = new_children
15233

153-
def empty(self) -> bool:
154-
"""
155-
Returns True if the tree does not have any element(s).
156-
False if the tree has element(s).
157-
158-
>>> BinarySearchTree().empty()
159-
True
160-
>>> BinarySearchTree().insert(1).empty()
161-
False
162-
>>> BinarySearchTree().insert(8, 3, 6, 1, 10, 14, 13, 4, 7).empty()
163-
False
164-
"""
165-
return not self.root
166-
16734
def __insert(self, value) -> None:
168-
"""
169-
Insert a new node in Binary Search Tree with value label
170-
"""
171-
new_node = Node(value) # create a new Node
172-
if self.empty(): # if Tree is empty
173-
self.root = new_node # set its root
174-
else: # Tree is not empty
175-
parent_node = self.root # from root
176-
if parent_node is None:
177-
return
178-
while True: # While we don't get to a leaf
179-
if value < parent_node.value: # We go left
35+
new_node = Node(value)
36+
if self.empty():
37+
self.root = new_node
38+
else:
39+
parent_node = self.root
40+
while True:
41+
if value < parent_node.value:
18042
if parent_node.left is None:
181-
parent_node.left = new_node # We insert the new node in a leaf
43+
parent_node.left = new_node
18244
break
18345
else:
18446
parent_node = parent_node.left
@@ -189,163 +51,43 @@ def __insert(self, value) -> None:
18951
parent_node = parent_node.right
19052
new_node.parent = parent_node
19153

192-
def insert(self, *values) -> Self:
193-
for value in values:
194-
self.__insert(value)
195-
return self
196-
def search(self, value) -> Node | None:
197-
"""
198-
>>> tree = BinarySearchTree().insert(10, 20, 30, 40, 50)
199-
>>> tree.search(10)
200-
{'10': (None, {'20': (None, {'30': (None, {'40': (None, 50)})})}
201-
>>> tree.search(20)
202-
{'20': (None, {'30': (None, {'40': (None, 50)})})}
203-
>>> tree.search(30)
204-
{'30': (None, {'40': (None, 50)})}
205-
>>> tree.search(40)
206-
{'40': (None, 50)}
207-
>>> tree.search(50)
208-
50
209-
>>> tree.search(5) is None # element not present
210-
True
211-
>>> tree.search(0) is None # element not present
212-
True
213-
>>> tree.search(-5) is None # element not present
214-
True
215-
>>> BinarySearchTree().search(10)
216-
Traceback (most recent call last):
217-
...
218-
IndexError: Warning: Tree is empty! please use another.
219-
"""
220-
54+
def search(self, value) -> Node | None:
22155
if self.empty():
22256
raise IndexError("Warning: Tree is empty! please use another.")
223-
else:
224-
node = self.root
225-
# use lazy evaluation here to avoid NoneType Attribute error
226-
while node is not None and node.value is not value:
227-
node = node.left if value < node.value else node.right
228-
return node
229-
230-
def get_max(self, node: Node | None = None) -> Node | None:
231-
"""
232-
We go deep on the right branch
233-
234-
>>> BinarySearchTree().insert(10, 20, 30, 40, 50).get_max()
235-
50
236-
>>> BinarySearchTree().insert(-5, -1, 0.1, -0.3, -4.5).get_max()
237-
{'0.1': (-0.3, None)}
238-
>>> BinarySearchTree().insert(1, 78.3, 30, 74.0, 1).get_max()
239-
{'78.3': ({'30': (1, 74.0)}, None)}
240-
>>> BinarySearchTree().insert(1, 783, 30, 740, 1).get_max()
241-
{'783': ({'30': (1, 740)}, None)}
242-
"""
243-
if node is None:
244-
if self.root is None:
245-
return None
246-
node = self.root
247-
248-
if not self.empty():
249-
while node.right is not None:
250-
node = node.right
251-
return node
252-
253-
def get_min(self, node: Node | None = None) -> Node | None:
254-
"""
255-
We go deep on the left branch
256-
257-
>>> BinarySearchTree().insert(10, 20, 30, 40, 50).get_min()
258-
{'10': (None, {'20': (None, {'30': (None, {'40': (None, 50)})})})}
259-
>>> BinarySearchTree().insert(-5, -1, 0, -0.3, -4.5).get_min()
260-
{'-5': (None, {'-1': (-4.5, {'0': (-0.3, None)})})}
261-
>>> BinarySearchTree().insert(1, 78.3, 30, 74.0, 1).get_min()
262-
{'1': (None, {'78.3': ({'30': (1, 74.0)}, None)})}
263-
>>> BinarySearchTree().insert(1, 783, 30, 740, 1).get_min()
264-
{'1': (None, {'783': ({'30': (1, 740)}, None)})}
265-
"""
266-
if node is None:
267-
node = self.root
268-
if self.root is None:
269-
return None
270-
if not self.empty():
271-
node = self.root
272-
while node.left is not None:
273-
node = node.left
57+
node = self.root
58+
while node is not None and node.value != value:
59+
node = node.left if value < node.value else node.right
27460
return node
27561

27662
def remove(self, value: int) -> None:
277-
# Look for the node with that label
27863
node = self.search(value)
27964
if node is None:
280-
msg = f"Value {value} not found"
281-
raise ValueError(msg)
65+
raise ValueError(f"Value {value} not found")
28266

283-
if node.left is None and node.right is None: # If it has no children
67+
if node.left is None and node.right is None:
28468
self.__reassign_nodes(node, None)
285-
elif node.left is None: # Has only right children
69+
elif node.left is None:
28670
self.__reassign_nodes(node, node.right)
287-
elif node.right is None: # Has only left children
71+
elif node.right is None:
28872
self.__reassign_nodes(node, node.left)
28973
else:
290-
predecessor = self.get_max(
291-
node.left
292-
) # Gets the max value of the left branch
293-
self.remove(predecessor.value) # type: ignore[union-attr]
294-
node.value = (
295-
predecessor.value # type: ignore[union-attr]
296-
) # Assigns the value to the node to delete and keep tree structure
297-
298-
def preorder_traverse(self, node: Node | None) -> Iterable:
299-
if node is not None:
300-
yield node # Preorder Traversal
301-
yield from self.preorder_traverse(node.left)
302-
yield from self.preorder_traverse(node.right)
303-
304-
def traversal_tree(self, traversal_function=None) -> Any:
305-
"""
306-
This function traversal the tree.
307-
You can pass a function to traversal the tree as needed by client code
308-
"""
309-
if traversal_function is None:
310-
return self.preorder_traverse(self.root)
311-
else:
312-
return traversal_function(self.root)
313-
def inorder(self, arr: list, node: Node | None) -> None:
314-
"""Perform an inorder traversal and append values of the nodes to
315-
a list named arr"""
316-
if node:
317-
self.inorder(arr, node.left)
318-
arr.append(node.value)
319-
self.inorder(arr, node.right)
320-
321-
def find_kth_smallest(self, k: int, node: Node) -> int:
322-
"""Return the kth smallest element in a binary search tree"""
323-
arr: list[int] = []
324-
self.inorder(arr, node) # append all values to list using inorder traversal
325-
return arr[k - 1]
326-
74+
predecessor = self.get_max(node.left)
75+
self.remove(predecessor.value)
76+
node.value = predecessor.value
32777

78+
# 修复的递归函数
32879
def inorder(curr_node: Node | None) -> list[Node]:
329-
"""
330-
inorder (left, self, right)
331-
"""
332-
node_list = []
333-
if curr_node is not None:
334-
node_list = [*inorder(curr_node.left), curr_node, *inorder(curr_node.right)]
335-
return node_list
336-
80+
"""Inorder traversal (left, self, right)"""
81+
if curr_node is None:
82+
return []
83+
return inorder(curr_node.left) + [curr_node] + inorder(curr_node.right)
33784

33885
def postorder(curr_node: Node | None) -> list[Node]:
339-
"""
340-
postOrder (left, right, self)
341-
"""
342-
node_list = []
343-
if curr_node is not None:
344-
node_list = postorder(curr_node.left) + postorder(curr_node.right) + [curr_node]
345-
return node_list
346-
86+
"""Postorder traversal (left, right, self)"""
87+
if curr_node is None:
88+
return []
89+
return postorder(curr_node.left) + postorder(curr_node.right) + [curr_node]
34790

34891
if __name__ == "__main__":
34992
import doctest
350-
35193
doctest.testmod(verbose=True)

0 commit comments

Comments
 (0)