Determining whether a given binary tree adheres to the rules of a Binary Search Tree (BST) is a common problem in computer science. A BST is a node-based binary tree data structure where each node has a value greater than all values in its left subtree and less than all values in its right subtree. This post will look at efficient Pythonic ways to solve this problem.
Understanding the Problem
Before diving into the code, let’s recap the defining characteristic of a BST:
- For every node in the tree:
- The value of the node is greater than the value of every node in its left subtree.
- The value of the node is less than the value of every node in its right subtree.
Recursive Approach
A recursive approach is often the most elegant and intuitive way to solve this problem. The function will recursively check each subtree to ensure they satisfy the BST property. We’ll use a helper function to pass along minimum and maximum bounds for each subtree.
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def is_bst_recursive(node, min_val, max_val):
"""
Recursively checks if a binary tree is a BST.
Args:
node: The root node of the subtree being checked.
min_val: The minimum allowed value for nodes in this subtree.
max_val: The maximum allowed value for nodes in this subtree.
Returns:
True if the subtree is a BST, False otherwise.
"""
if node is None:
return True
if not (min_val < node.data < max_val):
return False
return (is_bst_recursive(node.left, min_val, node.data) and
is_bst_recursive(node.right, node.data, max_val))
# Example usage:
= Node(2)
root = Node(1)
root.left = Node(3)
root.right
print(f"Is the tree a BST? {is_bst_recursive(root, float('-inf'), float('inf'))}") #True
= Node(5)
root2 = Node(1)
root2.left = Node(4)
root2.right = Node(3)
root2.right.left = Node(6)
root2.right.right
print(f"Is the tree a BST? {is_bst_recursive(root2, float('-inf'), float('inf'))}") #False
# Is the tree a BST? True
# Is the tree a BST? False
Iterative Approach (Using Inorder Traversal)
An alternative approach involves an inorder traversal of the tree. The inorder traversal of a BST will always produce a sorted sequence. We can use this property to check if the tree is a BST.
def is_bst_iterative(root):
"""
Iteratively checks if a binary tree is a BST using inorder traversal.
Args:
root: The root node of the tree.
Returns:
True if the tree is a BST, False otherwise.
"""
= []
stack = float('-inf')
prev
while stack or root:
while root:
stack.append(root)= root.left
root = stack.pop()
root if root.data <= prev:
return False
= root.data
prev = root.right
root return True
#Example Usage (same trees as above)
print(f"Is the tree a BST? {is_bst_iterative(root)}") #True
print(f"Is the tree a BST? {is_bst_iterative(root2)}") #False
# Is the tree a BST? True
# Is the tree a BST? False
Both the recursive and iterative approaches provide efficient solutions to the problem of determining whether a given binary tree is a BST. The choice between them often comes down to personal preference and the specific context of the application. The recursive approach is generally easier to understand, while the iterative approach can be slightly more efficient in terms of memory usage for very large trees.