import re
from collections import deque
class TreeNode:
def __init__(self, value):
if not isinstance(value, int) or value < 0 or value >= 100:
raise ValueError("Node value must be a whole non-negative integer less
than 100.")
[Link] = value
[Link] = None
[Link] = None
[Link] = None
class Tree:
def __init__(self, root_value):
[Link] = TreeNode(root_value)
def add(self, parent_value, child_value):
if not isinstance(child_value, int) or child_value < 0 or child_value >=
100:
raise ValueError("Child value must be a whole non-negative integer less
than 100.")
if child_value == [Link]:
raise ValueError("Child value cannot be the same as the root value.
Please enter a different value.")
# Check if the parent node exists
parent_node = self.find_node([Link], parent_value)
if not parent_node:
raise ValueError(f"Parent node with value {parent_value} not found.")
# Prevent adding duplicate values
if self.find_node([Link], child_value):
raise ValueError("Child value already exists in the tree.")
# Logic for adding the child node
if child_value < parent_node.value:
# Go to left child
if parent_node.left is None:
parent_node.left = TreeNode(child_value)
parent_node.[Link] = parent_node
else:
[Link](parent_node.[Link], child_value)
else:
# Go to right child
if parent_node.right is None:
parent_node.right = TreeNode(child_value)
parent_node.[Link] = parent_node
else:
[Link](parent_node.[Link], child_value)
print("Child added successfully.")
self.display_tree()
def _insert_node(self, node, child_value):
if child_value < [Link]:
if [Link] is None:
[Link] = TreeNode(child_value)
[Link] = node
else:
raise ValueError(f"Node with value {[Link]} already has a left
child.")
elif child_value > [Link]:
if [Link] is None:
[Link] = TreeNode(child_value)
[Link] = node
else:
raise ValueError(f"Node with value {[Link]} already has a right
child.")
def find_node(self, current_node, value):
if current_node is None:
return None
if current_node.value == value:
return current_node
left_result = self.find_node(current_node.left, value)
if left_result is not None:
return left_result
return self.find_node(current_node.right, value)
def update(self, old_value, new_value):
if not isinstance(new_value, int) or new_value < 0 or new_value >= 100:
raise ValueError("New value must be a whole non-negative integer less
than 100.")
node_to_update = self.find_node([Link], old_value)
if node_to_update is None:
raise ValueError(f"Node with value {old_value} not found.")
parent = node_to_update.parent
# Ensure the new value does not violate the BST property with respect to
the parent
if parent:
if [Link] == node_to_update and new_value >= [Link]:
raise ValueError("The new value should be less than the parent.")
elif [Link] == node_to_update and new_value <= [Link]:
raise ValueError("The new value should be greater than the
parent.")
# If both left and right children exist, check if new_value is within their
range
if node_to_update.left and node_to_update.right:
if not (node_to_update.[Link] < new_value <
node_to_update.[Link]):
raise ValueError("The new value should be greater than the left
child and less than the right child.")
# If only the left child exists, ensure new_value is greater than it
elif node_to_update.left:
if new_value <= node_to_update.[Link]:
raise ValueError("The new value should be greater than the left
child.")
# If only the right child exists, ensure new_value is less than it
elif node_to_update.right:
if new_value >= node_to_update.[Link]:
raise ValueError("The new value should be less than the right
child.")
# Update the node value if all checks pass
node_to_update.value = new_value
print("Node updated successfully.")
self.display_tree()
def delete(self, value):
if value == [Link]:
raise ValueError("Cannot delete the root node.")
[Link] = self._delete_recursive([Link], value)
print(f"Node with value {value} deleted.")
self.display_tree()
def _delete_recursive(self, node, value):
if node is None:
raise ValueError(f"Node with value {value} not found.")
if value < [Link]:
[Link] = self._delete_recursive([Link], value)
elif value > [Link]:
[Link] = self._delete_recursive([Link], value)
else:
# Node to delete is found
# Case 1: Node with two children
if [Link] and [Link]:
# Check if the node is a left or right child of its parent
if node == [Link]:
# For left child, replace with the smallest node in the left
subtree
min_left = self._find_min([Link])
[Link] = min_left.value
[Link] = self._delete_recursive([Link], min_left.value)
else:
# For right child, replace with the largest node in the right
subtree
max_right = self._find_max([Link])
[Link] = max_right.value
[Link] = self._delete_recursive([Link],
max_right.value)
elif [Link]:
node = [Link]
elif [Link]:
node = [Link]
else:
return None
return node
def _find_min(self, node):
current = node
while [Link] is not None:
current = [Link]
return current
def _find_max(self, node):
current = node
while [Link] is not None:
current = [Link]
return current
def display_tree(self):
if [Link] is None:
print("Empty tree")
return
levels = self._get_levels([Link])
output = []
for level in levels:
row = []
for node, spacing in level:
if node:
label = "root: " if node == [Link] else ("L: " if [Link]
< [Link] else "R: ")
[Link](f"{label}{[Link]}".center(spacing))
else:
[Link](" " * spacing)
[Link]("".join(row))
print("\nCurrent Tree Structure:")
for line in output:
print(line)
def display_subtree(self, node_value):
subtree_root = self.find_node([Link], node_value)
if subtree_root is None:
print(f"No node with value {node_value} found.")
return
print(f"\nDisplaying Subtree rooted at {node_value}:")
subtree = Tree(subtree_root.value) # Temporary tree to visualize subtree
only
[Link] = subtree_root
subtree.display_tree()
def display_leaf_nodes(self):
print("\nLeaf Nodes:")
self._print_leaf_nodes([Link])
def _print_leaf_nodes(self, node):
if node:
if not [Link] and not [Link]:
print([Link])
self._print_leaf_nodes([Link])
self._print_leaf_nodes([Link])
def display_siblings(self, parent_value):
parent_node = self.find_node([Link], parent_value)
if not parent_node:
print(f"Parent node with value {parent_value} not found.")
return
siblings = []
if parent_node.left:
[Link](parent_node.[Link])
if parent_node.right:
[Link](parent_node.[Link])
if siblings:
print(f"Siblings of {parent_value}: {', '.join(map(str, siblings))}")
else:
print("No siblings found.")
def display_root(self):
print(f"\nRoot Node: {[Link]}")
def display_parents(self):
print("\nParent Nodes:")
self._print_parents([Link])
def _print_parents(self, node):
if node:
if [Link] or [Link]:
print([Link])
self._print_parents([Link])
self._print_parents([Link])
def display_children(self):
print("\nChild Nodes:")
self._print_children([Link])
def _print_children(self, node):
if node:
if [Link]:
print([Link])
if [Link]:
print([Link])
self._print_children([Link])
self._print_children([Link])
def tree_level(self):
print("\nTree Level (Height):", self._get_tree_level([Link]))
def _get_tree_level(self, node):
if node is None:
return 0
return max(self._get_tree_level([Link]),
self._get_tree_level([Link])) + 1
def _get_levels(self, root):
levels = []
queue = deque([(root, 0)])
max_depth = self._get_tree_level(root)
while queue:
level_size = len(queue)
level = []
for _ in range(level_size):
node, depth = [Link]()
spacing = (2 ** (max_depth - depth + 1)) - 1
[Link]((node, spacing))
if node:
if [Link]:
[Link] = node
if [Link]:
[Link] = node
[Link](([Link], depth + 1))
[Link](([Link], depth + 1))
[Link](level)
return levels
def main():
while True:
root_value = input("Enter the root value (must be a whole number < 100):
").strip()
if [Link](r"^(1|[1-9][0-9]?)$", root_value):
root_value = int(root_value)
break
else:
print("Invalid input. Please enter a whole number between 1 and 99.")
tree = Tree(root_value)
tree.display_tree()
while True:
print("\nAvailable commands:")
print("add <parent> <child> - Add a child node")
print("update <old> <new> - Update a node's value")
print("delete <node> - Delete a node")
print("display_leaf_nodes - Display all leaf nodes")
print("display_siblings <parent> - Display siblings of given parent node")
print("display_root - Display root node")
print("display_parents - Display all parent nodes")
print("display_children - Display all child nodes")
print("tree_level - Display the level (height) of the tree")
print("display_tree - Display the current tree structure")
print("display_subtree <node> - Display the subtree rooted at a given
node")
print("exit - Exit the program")
command_input = input("Enter command: ").strip()
command_parts = command_input.split()
if not command_parts:
continue
command = command_parts[0].lower()
try:
if command == "add" and len(command_parts) == 3:
parent_value = int(command_parts[1])
child_value = int(command_parts[2])
[Link](parent_value, child_value)
elif command == "update" and len(command_parts) == 3:
old_value = int(command_parts[1])
new_value = int(command_parts[2])
[Link](old_value, new_value)
elif command == "delete" and len(command_parts) == 2:
node_value = int(command_parts[1])
[Link](node_value)
elif command == "leafNodes":
tree.display_leaf_nodes()
elif command == "siblings" and len(command_parts) == 2:
parent_value = int(command_parts[1])
tree.display_siblings(parent_value)
elif command == "root":
tree.display_root()
elif command == "parents":
tree.display_parents()
elif command == "children":
tree.display_children()
elif command == "level":
tree.tree_level()
elif command == "display tree":
tree.display_tree()
elif command == "subtree" and len(command_parts) == 2:
node_value = int(command_parts[1])
tree.display_subtree(node_value)
elif command == "exit":
print("Exiting...")
break
else:
print("Invalid command or wrong number of arguments.")
except ValueError as e:
print("Error:", e)
if __name__ == "__main__":
main()