nathanwailes

Binary trees

Jun 10th, 2024 (edited)
469
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.08 KB | None | 0 0
  1. """
  2. - Create the TreeNode class.
  3. - height()
  4. - size()
  5. - count_leaves()
  6. - preorder_traversal()
  7. - inorder_traversal()
  8. - postorder_traversal()
  9. - level_order_traversal()
  10. - mirror()
  11. - is_complete_tree()
  12. - find_lca()
  13. - insert()
  14. - delete()
  15. """
  16. class TreeNode:
  17.     def __init__(self, value=0, left=None, right=None):
  18.         self.value = value
  19.         self.left = left
  20.         self.right = right
  21.  
  22. # Height Calculation
  23. def height(node):
  24.     if node is None:
  25.         return -1
  26.     return max(height(node.left), height(node.right)) + 1
  27.  
  28. # Size Calculation
  29. def size(node):
  30.     if node is None:
  31.         return 0
  32.     return size(node.left) + size(node.right) + 1
  33.  
  34. # Counting the number of leaf nodes
  35. def count_leaves(node):
  36.     if node is None:
  37.         return 0
  38.     if node.left is None and node.right is None:
  39.         return 1
  40.     return count_leaves(node.left) + count_leaves(node.right)
  41.  
  42. # Traversals: Pre-order, In-order, Post-order, Level-order
  43. def preorder_traversal(root):
  44.     return [root.value] + preorder_traversal(root.left) + preorder_traversal(root.right) if root else []
  45.  
  46. def inorder_traversal(root):
  47.     return inorder_traversal(root.left) + [root.value] + inorder_traversal(root.right) if root else []
  48.  
  49. def postorder_traversal(root):
  50.     return postorder_traversal(root.left) + postorder_traversal(root.right) + [root.value] if root else []
  51.  
  52. def level_order_traversal(root):
  53.     if not root:
  54.         return []
  55.     result, queue = [], [root]
  56.     while queue:
  57.         node = queue.pop(0)
  58.         result.append(node.value)
  59.         if node.left:
  60.             queue.append(node.left)
  61.         if node.right:
  62.             queue.append(node.right)
  63.     return result
  64.  
  65. # Mirroring (inverting) the binary tree
  66. def mirror(node):
  67.     if node is None:
  68.         return None
  69.     node.left, node.right = node.right, node.left
  70.     mirror(node.left)
  71.     mirror(node.right)
  72.     return node
  73.  
  74. # Checking if the binary tree is complete
  75. def is_complete_tree(root):
  76.     if not root:
  77.         return True
  78.     queue = [root]
  79.     end = False
  80.     while queue:
  81.         current = queue.pop(0)
  82.         if current:
  83.             if end:
  84.                 return False
  85.             queue.append(current.left)
  86.             queue.append(current.right)
  87.         else:
  88.             end = True
  89.     return True
  90.  
  91. def find_lca(root, n1, n2):
  92.     """
  93.    The lowest common ancestor is the deepest node that has both nodes as descendants.
  94.    """
  95.     # Base case
  96.     if root is None:
  97.         return None
  98.  
  99.     # If either n1 or n2 matches with root's value, report the presence by returning root
  100.     if root.value == n1 or root.value == n2:
  101.         return root
  102.  
  103.     # Look for keys in left and right subtrees
  104.     left_lca = find_lca(root.left, n1, n2)
  105.     right_lca = find_lca(root.right, n1, n2)
  106.  
  107.     # If both of the above calls return non-NULL, then one key is present in one subtree
  108.     # and the other is present in the other, so this node is the LCA
  109.     if left_lca and right_lca:
  110.         return root
  111.  
  112.     # Otherwise check if left subtree or right subtree is LCA
  113.     return left_lca if left_lca is not None else right_lca
  114.  
  115. # Insertion: Adds a node to the binary tree (level-order insertion for simplicity)
  116. def insert(root, value):
  117.     if root is None:
  118.         return TreeNode(value)
  119.    
  120.     queue = [root]
  121.     while queue:
  122.         current = queue.pop(0)
  123.        
  124.         if current.left is None:
  125.             current.left = TreeNode(value)
  126.             break
  127.         else:
  128.             queue.append(current.left)
  129.        
  130.         if current.right is None:
  131.             current.right = TreeNode(value)
  132.             break
  133.         else:
  134.             queue.append(current.right)
  135.    
  136.     return root
  137.  
  138. # Deletion: Removes a node from the binary tree (simple level-order approach)
  139. def delete(root, value):
  140.     if root is None:
  141.         return None
  142.    
  143.     if root.left is None and root.right is None:
  144.         if root.value == value:
  145.             return None
  146.         else:
  147.             return root
  148.    
  149.     key_node = None
  150.     queue = [root]
  151.     temp = None
  152.     while queue:
  153.         temp = queue.pop(0)
  154.         if temp.value == value:
  155.             key_node = temp
  156.        
  157.         if temp.left:
  158.             queue.append(temp.left)
  159.         if temp.right:
  160.             queue.append(temp.right)
  161.    
  162.     if key_node:
  163.         x = temp.value
  164.         _delete_deepest(root, temp)
  165.         key_node.value = x
  166.    
  167.     return root
  168.  
  169. def _delete_deepest(root, del_node):
  170.     queue = [root]
  171.     while queue:
  172.         temp = queue.pop(0)
  173.         if temp is del_node:
  174.             temp = None
  175.             return
  176.         if temp.right:
  177.             if temp.right is del_node:
  178.                 temp.right = None
  179.                 return
  180.             else:
  181.                 queue.append(temp.right)
  182.         if temp.left:
  183.             if temp.left is del_node:
  184.                 temp.left = None
  185.                 return
  186.             else:
  187.                 queue.append(temp.left)
  188.  
  189. # Example usage
  190. root = TreeNode(1)
  191. root = insert(root, 2)
  192. root = insert(root, 3)
  193. root = insert(root, 4)
  194. root = insert(root, 5)
  195.  
  196. # Example usage
  197. root = TreeNode(1)
  198. root.left = TreeNode(2)
  199. root.right = TreeNode(3)
  200. root.left.left = TreeNode(4)
  201. root.left.right = TreeNode(5)
  202.  
  203. print("Size of the tree:", size(root))
  204. print("Height of the tree:", height(root))
  205. print("Number of leaf nodes:", count_leaves(root))  # Output: 3
  206. print("Is the tree complete?", is_complete_tree(root))  # Output: True
  207.  
  208. print("Pre-order traversal:", preorder_traversal(root))
  209. print("In-order traversal:", inorder_traversal(root))
  210. print("Post-order traversal:", postorder_traversal(root))
  211. print("Level-order traversal:", level_order_traversal(root))
  212.  
  213. root = mirror(root)
  214. print("Level-order traversal after mirroring:", level_order_traversal(root))  # Output: [1, 3, 2, 5, 4]
  215.  
  216. root = insert(root, 8)
  217. print("Level-order traversal after inserting 8:", level_order_traversal(root))
  218.  
  219. root = delete(root, 3)
  220. print("Level-order traversal after deleting 3:", level_order_traversal(root))
  221.  
  222. print("Lowest common ancestor of 5 and 4:", find_lca(root, 5, 4).value)
Advertisement
Add Comment
Please, Sign In to add comment