The following is a comprehensive, detailed lecture summary of MIT 6.006: Binary Trees, Part 1. 🌳 Binary Trees: Data Structures & Algorithms Lecture: 6. Binary Trees, Part 1 Source: MIT OpenCourseWare Goal: Implement a data structure that supports fast (logarithmic) operations for both Sequences (insert/delete in middle) and Sets (predecessor/successor queries).

  1. Motivation: The "Best of All Worlds" Existing data structures have trade-offs. We want a single structure that performs efficiently across the board. | Data Structure | Indexing get_at(i) | Insert/Delete (Ends) | Insert/Delete (Middle) | Find (Key) | Find Prev/Next | |---|---|---|---|---|---| | Array | O(1) | O(n) (shift) | O(n) | O(n) | O(n) | | Sorted Array | O(1) | O(n) | O(n) | O(\log n) | O(\log n) | | Linked List | O(n) | O(1) | O(1)* | O(n) | O(n) | | Hash Table | N/A | O(1) | N/A | O(1) | O(n) | | Binary Tree | O(\log n)** | O(\log n) | O(\log n) | O(\log n) | O(\log n) | *If we already have a pointer to the location. **Requires a balanced tree (Topic of Part 2). The Goal: Achieve O(h) time for all operations, where h is the height of the tree. In a balanced tree, h = O(\log n).
  2. Anatomy of a Binary Tree A Rooted Binary Tree is a set of nodes where each node has pointers to a parent, a left child, and a right child. Node Structure class BinaryNode: def init(self, item): self.item = item self.parent = None self.left = None self.right = None

Key Definitions

  1. Traversal Order (In-Order) The binary tree implicitly maintains a linear ordering of items called the Traversal Order (or In-Order Traversal). Recursive Definition For any node x, the order is:
  1. Tree Navigation Operations All operations run in O(h) time. 4.1 Subtree First / Last Find the first (or last) node in the traversal order within a specific subtree.

def subtree_first(node): if node is None: return None while node.left is not None: node = node.left return node

def subtree_last(node): if node is None: return None while node.right is not None: node = node.right return node

4.2 Successor / Predecessor Find the node that immediately follows (or precedes) a given node in the global traversal order. Logic for Successor(node):

def successor(node): # Case 1: Right subtree exists if node.right is not None: return subtree_first(node.right)

# Case 2: No right subtree, walk up
while node.parent is not None and node is node.parent.right:
    node = node.parent
return node.parent  # Returns None if node is the last in the tree
  1. Dynamic Operations (Insert & Delete) These operations modify the tree structure while maintaining the traversal order. 5.1 Insert After Insert a new node new immediately after an existing node node in the traversal order.

graph TD subgraph Case 1: No Right Child A((A)) -.->|Insert B after A| B((B)) end

subgraph Case 2: Right Child Exists
X((X)) --> Y((Y))
Y --> Z((Z))
Z -.->|Insert New after X| N((New))

note[Z is Successor of X]
end

def insert_after(node, new_node): if node.right is None: node.right = new_node new_node.parent = node else: succ = successor(node) # In this case, succ is subtree_first(node.right) succ.left = new_node new_node.parent = succ

5.2 Delete Remove a node from the tree.

  1. Applications: Sets vs. Sequences The binary tree is a container. How we map data to the Traversal Order determines the data structure type. Set (Binary Search Tree - BST)
  1. Summary & Complexity All operations discussed today run in time proportional to the height of the tree. | Operation | Complexity | Description | |---|---|---| | subtree_first/last | O(h) | Walk down to leaf. | | successor/predecessor | O(h) | Walk up/down (worst case root-to-leaf). | | insert_after/before | O(h) | Uses successor + constant pointer changes. | | delete | O(h) | Swaps item down to leaf level. | | find (BST) | O(h) | Standard binary search path. | The Problem: In the worst case (e.g., inserting sorted data into a raw BST), the tree becomes a linked list where h = n.