diff --git a/src/datastructpy/non_linear/trees/binary_search_tree.py b/src/datastructpy/non_linear/trees/binary_search_tree.py index 81ca244..f1c12dd 100644 --- a/src/datastructpy/non_linear/trees/binary_search_tree.py +++ b/src/datastructpy/non_linear/trees/binary_search_tree.py @@ -1,3 +1,7 @@ +from datastructpy.node import Node +from datastructpy.non_linear.trees.breadth_first_search import breadth_first_search +from datastructpy.non_linear.trees.depth_first_search import depth_first_search + class BinarySearchTree: """ A class representing a binary search tree (BST). @@ -51,25 +55,34 @@ def insert(self, key): print(bst.root.right.key) # Output: 15 """ - def search(self, key): + def search(self, key, algorithm='dfs'): """ - Checks if a value exists in the Binary Search Tree (BST). + Searches for a key in the Binary Search Tree (BST) using the specified algorithm. + + This method allows searching for a key in the BST using either + depth-first search (DFS) or breadth-first search (BFS). - This method traverses the BST to determine if a node with the specified key exists. - It starts from the root and: - - Returns True if a node with the given key is found. - - Returns False if the key is not present in the tree. + - DFS (default)**: Searches by exploring as deep as possible before backtracking. + - BFS: Searches level by level, ensuring the shortest path to a node is checked first. Parameters ---------- key : int The value to search for in the tree. + algorithm : str, optional + The search algorithm to use ('dfs' for Depth-First Search or 'bfs' for Breadth-First Search). + Defaults to 'dfs'. Returns ------- - bool - - True if a node with the specified key exists in the tree. - - False if the key does not exist or the tree is empty. + Node or None + - The Node object containing the specified key if found. + - None if the key does not exist or the tree is empty. + + Raises + ------ + ValueError + If an invalid algorithm is provided. Examples -------- @@ -80,9 +93,18 @@ def search(self, key): bst.insert(15) # Searching for values in the tree - print(bst.search(5)) # Output: True (5 exists in the tree) - print(bst.search(20)) # Output: False (20 does not exist in the tree) + result = bst.search(5) + if result: + print(result.key) # Output: 5 + + print(bst.search(20)) # Output: None (20 does not exist in the tree) """ + if algorithm == 'bfs': + return breadth_first_search(self.root, key) + elif algorithm == 'dfs': + return depth_first_search(self.root, key) + else: + raise ValueError(f"Invalid search algorithm: {algorithm}. Use 'dfs' or 'bfs'.") def delete(self, key): """Delete a value from the BST. diff --git a/src/datastructpy/non_linear/trees/breadth_first_search.py b/src/datastructpy/non_linear/trees/breadth_first_search.py new file mode 100644 index 0000000..7ef2404 --- /dev/null +++ b/src/datastructpy/non_linear/trees/breadth_first_search.py @@ -0,0 +1,32 @@ +from collections import deque +from datastructpy.node import Node + +def breadth_first_search(root, key): + """ + Performs a breadth-first search (BFS) on a binary search tree. + + Parameters: + ---------- + root (Node): The root of the BST. + key (int): The value to search for. + + Returns: + ---------- + Node or None: The node containing the key, or None if not found. + """ + if not root: + return None + + queue = deque([root]) + + while queue: + node = queue.popleft() + if node.key == key: + return node # Found the key + + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + return None # Key not found \ No newline at end of file diff --git a/src/datastructpy/non_linear/trees/depth_first_search.py b/src/datastructpy/non_linear/trees/depth_first_search.py new file mode 100644 index 0000000..1b33f89 --- /dev/null +++ b/src/datastructpy/non_linear/trees/depth_first_search.py @@ -0,0 +1,28 @@ +from datastructpy.node import Node + +def depth_first_search(root, key): + """ + Performs a depth-first search (DFS) on a binary search tree. + + Parameters: + ---------- + root (Node): The root of the BST. + key (int): The value to search for. + + Returns: + ---------- + Node or None: The node containing the key, or None if not found. + """ + if not root: + return None + + if root.key == key: + return root # Found the key + + # Search left subtree + left_result = depth_first_search(root.left, key) + if left_result: + return left_result + + # Search right subtree + return depth_first_search(root.right, key) \ No newline at end of file diff --git a/tests/non-linear/trees/binary_search_tree/test_search.py b/tests/non-linear/trees/binary_search_tree/test_search.py index 1be09b5..5053ee7 100644 --- a/tests/non-linear/trees/binary_search_tree/test_search.py +++ b/tests/non-linear/trees/binary_search_tree/test_search.py @@ -1 +1,77 @@ +import pytest from datastructpy.non_linear.trees.binary_search_tree import BinarySearchTree + +@pytest.fixture +def bst(): + r""" + Fixture to create a Binary Search Tree (BST) with predefined values. + + The tree structure: + 10 + / \ + 5 15 + / \ / \ + 3 7 13 18 + """ + elements = [10, 5, 15, 3, 7, 13, 18] + return BinarySearchTree.list_to_tree(elements) + +@pytest.mark.parametrize("key, expected", [ + (10, True), # Root node + (5, True), # Left child of root + (15, True), # Right child of root + (3, True), # Left child of 5 + (7, True), # Right child of 5 + (13, True), # Left child of 15 + (18, True), # Right child of 15 + (20, False), # Not in tree + (-1, False), # Not in tree +]) +def test_search_dfs(bst, key, expected): + """ + Tests depth-first search (DFS) in BST. + Ensures DFS correctly identifies if a key exists in the tree. + """ + result = bst.search(key, algorithm='dfs') + assert (result is not None) == expected + +@pytest.mark.parametrize("key, expected", [ + (10, True), # Root node + (5, True), # Left child of root + (15, True), # Right child of root + (3, True), # Left child of 5 + (7, True), # Right child of 5 + (13, True), # Left child of 15 + (18, True), # Right child of 15 + (20, False), # Not in tree + (-1, False), # Not in tree +]) +def test_search_bfs(bst, key, expected): + """ + Tests breadth-first search (BFS) in BST. + Ensures BFS correctly identifies if a key exists in the tree. + """ + result = bst.search(key, algorithm='bfs') + assert (result is not None) == expected + +def test_search_default_algorithm(bst): + """ + Ensures that search() defaults to DFS when no algorithm is specified. + """ + assert bst.search(7) is not None # Should be found using DFS + assert bst.search(20) is None # Should not be found + +def test_search_empty_tree(): + """ + Tests searching in an empty BST. + The search should return None for any key. + """ + empty_bst = BinarySearchTree() + assert empty_bst.search(10) is None # Should return None + +def test_search_invalid_algorithm(bst): + """ + Tests if search() handles invalid algorithm names properly. + """ + with pytest.raises(ValueError): + bst.search(10, algorithm='invalid_algorithm') \ No newline at end of file