Skip to content

Commit f0fb029

Browse files
keonclaude
andcommitted
Structural cleanup: remove empty dirs, rewrite bst.py, fix test bug
- Remove empty placeholder directories automata/, distribution/, ml/, unix/ that contained no implementations (#2724) - Rewrite data_structures/bst.py: add type hints, make traversals return lists instead of printing, prefix internal helpers with _, fix O(log n) → O(n) complexity claim, remove embedded unittest (#2726) - Fix test_insertion_sort to actually test insertion_sort instead of bitonic_sort (copy-paste error) (#2735) Closes #2724, closes #2726, closes #2735 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 053cab1 commit f0fb029

2 files changed

Lines changed: 72 additions & 113 deletions

File tree

algorithms/data_structures/bst.py

Lines changed: 70 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,106 @@
1+
"""Binary Search Tree implementation.
2+
3+
A BST is a node-based binary tree where each node's left subtree contains
4+
only nodes with data less than the node's data, and the right subtree
5+
contains only nodes with data greater than the node's data.
6+
7+
Operations and complexities (n = number of nodes):
8+
- insert: O(log n) average, O(n) worst case
9+
- search: O(log n) average, O(n) worst case
10+
- size: O(n)
11+
- preorder: O(n)
12+
- inorder: O(n)
13+
- postorder: O(n)
114
"""
2-
Implement Binary Search Tree. It has method:
3-
1. Insert
4-
2. Search
5-
3. Size
6-
4. Traversal (Preorder, Inorder, Postorder)
7-
"""
15+
from __future__ import annotations
816

9-
import unittest
17+
from typing import Optional
1018

1119

1220
class Node:
13-
def __init__(self, data):
14-
self.data = data
15-
self.left = None
16-
self.right = None
21+
def __init__(self, data: int) -> None:
22+
self.data: int = data
23+
self.left: Optional[Node] = None
24+
self.right: Optional[Node] = None
1725

1826

1927
class BST:
20-
def __init__(self):
21-
self.root = None
28+
def __init__(self) -> None:
29+
self.root: Optional[Node] = None
2230

23-
def get_root(self):
31+
def get_root(self) -> Optional[Node]:
2432
return self.root
2533

26-
"""
27-
Get the number of elements
28-
Using recursion. Complexity O(logN)
29-
"""
30-
31-
def size(self):
32-
return self.recur_size(self.root)
34+
def size(self) -> int:
35+
"""Return the number of nodes in the tree. Complexity: O(n)."""
36+
return self._recur_size(self.root)
3337

34-
def recur_size(self, root):
38+
def _recur_size(self, root: Optional[Node]) -> int:
3539
if root is None:
3640
return 0
37-
else:
38-
return 1 + self.recur_size(root.left) + self.recur_size(root.right)
41+
return 1 + self._recur_size(root.left) + self._recur_size(root.right)
3942

40-
"""
41-
Search data in bst
42-
Using recursion. Complexity O(logN)
43-
"""
43+
def search(self, data: int) -> bool:
44+
"""Return True if data exists in the tree. Complexity: O(log n) average."""
45+
return self._recur_search(self.root, data)
4446

45-
def search(self, data):
46-
return self.recur_search(self.root, data)
47-
48-
def recur_search(self, root, data):
47+
def _recur_search(self, root: Optional[Node], data: int) -> bool:
4948
if root is None:
5049
return False
5150
if root.data == data:
5251
return True
53-
elif data > root.data: # Go to right root
54-
return self.recur_search(root.right, data)
55-
else: # Go to left root
56-
return self.recur_search(root.left, data)
57-
58-
"""
59-
Insert data in bst
60-
Using recursion. Complexity O(logN)
61-
"""
52+
elif data > root.data:
53+
return self._recur_search(root.right, data)
54+
else:
55+
return self._recur_search(root.left, data)
6256

63-
def insert(self, data):
57+
def insert(self, data: int) -> bool:
58+
"""Insert data into the tree. Return False if data already exists. Complexity: O(log n) average."""
6459
if self.root:
65-
return self.recur_insert(self.root, data)
60+
return self._recur_insert(self.root, data)
6661
else:
6762
self.root = Node(data)
6863
return True
6964

70-
def recur_insert(self, root, data):
71-
if root.data == data: # The data is already there
65+
def _recur_insert(self, root: Node, data: int) -> bool:
66+
if root.data == data:
7267
return False
73-
elif data < root.data: # Go to left root
74-
if root.left: # If left root is a node
75-
return self.recur_insert(root.left, data)
76-
else: # left root is a None
68+
elif data < root.data:
69+
if root.left:
70+
return self._recur_insert(root.left, data)
71+
else:
7772
root.left = Node(data)
7873
return True
79-
else: # Go to right root
80-
if root.right: # If right root is a node
81-
return self.recur_insert(root.right, data)
74+
else:
75+
if root.right:
76+
return self._recur_insert(root.right, data)
8277
else:
8378
root.right = Node(data)
8479
return True
8580

86-
"""
87-
Preorder, Postorder, Inorder traversal bst
88-
"""
89-
90-
def preorder(self, root):
81+
def preorder(self, root: Optional[Node]) -> list[int]:
82+
"""Return list of node values in preorder (root, left, right)."""
83+
result: list[int] = []
9184
if root:
92-
print(str(root.data), end=" ")
93-
self.preorder(root.left)
94-
self.preorder(root.right)
95-
96-
def inorder(self, root):
85+
result.append(root.data)
86+
result.extend(self.preorder(root.left))
87+
result.extend(self.preorder(root.right))
88+
return result
89+
90+
def inorder(self, root: Optional[Node]) -> list[int]:
91+
"""Return list of node values in inorder (left, root, right)."""
92+
result: list[int] = []
9793
if root:
98-
self.inorder(root.left)
99-
print(str(root.data), end=" ")
100-
self.inorder(root.right)
101-
102-
def postorder(self, root):
94+
result.extend(self.inorder(root.left))
95+
result.append(root.data)
96+
result.extend(self.inorder(root.right))
97+
return result
98+
99+
def postorder(self, root: Optional[Node]) -> list[int]:
100+
"""Return list of node values in postorder (left, right, root)."""
101+
result: list[int] = []
103102
if root:
104-
self.postorder(root.left)
105-
self.postorder(root.right)
106-
print(str(root.data), end=" ")
107-
108-
109-
"""
110-
The tree is created for testing:
111-
112-
10
113-
/ \
114-
6 15
115-
/ \\ / \
116-
4 9 12 24
117-
/ / \
118-
7 20 30
119-
/
120-
18
121-
"""
122-
123-
124-
class TestSuite(unittest.TestCase):
125-
def setUp(self):
126-
self.tree = BST()
127-
self.tree.insert(10)
128-
self.tree.insert(15)
129-
self.tree.insert(6)
130-
self.tree.insert(4)
131-
self.tree.insert(9)
132-
self.tree.insert(12)
133-
self.tree.insert(24)
134-
self.tree.insert(7)
135-
self.tree.insert(20)
136-
self.tree.insert(30)
137-
self.tree.insert(18)
138-
139-
def test_search(self):
140-
self.assertTrue(self.tree.search(24))
141-
self.assertFalse(self.tree.search(50))
142-
143-
def test_size(self):
144-
self.assertEqual(11, self.tree.size())
145-
146-
147-
if __name__ == "__main__":
148-
unittest.main()
103+
result.extend(self.postorder(root.left))
104+
result.extend(self.postorder(root.right))
105+
result.append(root.data)
106+
return result

tests/test_sorting.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from algorithms.sorting import (
44
bitonic_sort,
55
bogo_sort,
6+
insertion_sort,
67
bubble_sort,
78
bucket_sort,
89
cocktail_shaker_sort,
@@ -60,7 +61,7 @@ def test_heap_sort(self):
6061
self.assertTrue(is_sorted(min_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232])))
6162

6263
def test_insertion_sort(self):
63-
self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232])))
64+
self.assertTrue(is_sorted(insertion_sort([1, 3, 2, 5, 65, 23, 57, 1232])))
6465

6566
def test_merge_sort(self):
6667
self.assertTrue(is_sorted(merge_sort([1, 3, 2, 5, 65, 23, 57, 1232])))

0 commit comments

Comments
 (0)