Comprehensive Study Guide on Tree Data Structures and Traversals

Overview of Tree Data Structures

  • Relationship to Linear Structures: Unlike lists, arrays, queues, stacks, and linked lists, which are linear and define elements only by what comes before and after them, trees are non-linear structures.

  • Hierarchical Order: Data in a tree is structured hierarchically, with some data positioned "above" and some "below" other data.

  • Applications in Science and Industry: Trees are used extensively in data science, databases, Artificial Intelligence (AI), computer graphics, and Operating Systems (OS).

  • Efficiency: Trees are often faster for certain operations compared to linear data structures.

  • Humorous/Contextual Examples: The introductory materials mention concepts like "Make Money Fast!", "Stock", "Fraud", "Ponzi Scheme", and "Bank Robbery" in relation to hierarchical or structural representations.

Defining the Tree Abstract Model

  • Conceptual Model: In computer science, a tree is an abstract model of a hierarchical structure.

  • Composition: A tree consists of nodes that maintain a parent-child relationship.

  • Real-World Hierarchical Applications:

    • Organization Charts: Example: Computers”R”Us which branches into Sales, Manufacturing, and R&D. Sales branches into US and International; US branches into Laptops and Desktops; International branches into Europe, Asia, and Canada.

    • File Systems: Directories containing sub-directories and files.

    • Programming Environments.

Fundamental Tree Terminology

  • Element Relationships: Each element in a tree has exactly one parent (except the root) and zero or more child elements.

  • Root: The node without a parent (e.g., node A in the provided diagram). It serves as the primary access point to the tree.

  • Internal Node: A node that has at least one child (e.g., A, B, C, F).

  • External Node (Leaf): A node that has zero children (e.g., E, I, J, K, G, H, D).

  • Ancestors of a Node: The parent, grandparent, great-grandparent, and so on, reaching back to the root.

  • Depth of a Node: The total number of ancestors the node has.

  • Height of a Tree: The maximum depth found at any node in the tree. For the example tree provided, the maximum height is 3.

  • Descendant of a Node: The child, grandchild, great-grandchild, and so on.

  • Subtree: A smaller tree structure consisting of a specific node and all of its descendants.

  • Siblings: Nodes that share the the same parent.

  • Edges: The connections between nodes. The root node is distinct because it has no incoming edge.

  • Path: The sequence of nodes discovered by following edges from the root to a specific destination node.

  • Recursive Nature: Trees are fundamentally recursive; every node can be considered the root of its own subtree.

  • Ordered Tree: A tree where the children of any given node are arranged in a specific, meaningful order.

The Binary Tree ADT

  • Definition: One of the most common tree types where each node can have a maximum of two children.

  • Child Designations: Left child and Right child.

  • Levels: Nodes are organized into levels, with the root defined as level 0.

  • Metric Comparisons (Diagram Cases a, b, and c):

    • Depth of node H: a) 3, b) 4, c) 7.

    • Height of trees: a) 3, b) 5, c) 7.

    • Width (maximum nodes at a single level): a) 4 (at level 2), b) 3 (at level 2), c) 1.

    • Size: Total number of nodes in the examples provided is 9.

  • Height Constraints:

    • If a tree has 6 nodes, its maximum height is 6 (occurring when there is exactly one node per level).

    • The minimum height of a tree with size nn is calculated as log2n\lceil \log_2 n \rceil.

    • Example: If a tree has 4 nodes (n=4n = 4), its minimum height is 2.

    • Algorithm Complexity: Tree height is a critical factor for calculating the time complexity of various algorithms.

Binary Tree Structural Classifications

  • Full Binary Tree: A tree where every internal node has either zero or exactly two children. No node has only one child.

  • Perfect Binary Tree: A tree where all possible node positions are filled from top to bottom. Every internal node has exactly two children, and all leaf nodes exist at the same level.

Python Implementation: The Binary Tree Node Class

  • Technical Structure: Each node is stored with links to its potential children.

  • Verbatim BinTreeNode Code:

  class _BinTreeNode:
      def __init__(self, element):
          self._element = element
          self._right = None
          self.left = None
  ```
- BinaryTree Constructor: This class initializes the root to a node containing a specific value.

python class BinaryTree: # BinaryTree initializes the root to a node with a value def init(self, root): self._root = _BinTreeNode(root)

myTree = BinaryTree(1)   ```

General Tree Traversal Concepts

  • Systematic Visitation: Traversal involves visiting every node in the tree in a specific order.

  • Running Time: The time constraint for traversing a tree is O(n)O(n), where nn represents the total number of nodes.

  • Traversal Categories:

    • Breadth-First Traversal (Width-first).

    • Depth-First Traversal (Involves Pre-order, In-order, and Post-order).

Depth-First Traversal Algorithms

  • Pre-order Traversal:

    • Logic: Starting at the root, a node is visited before its descendants. It follows the left node first.

    • Implementation: Uses recursion; the base case is encountering a NULL child.

    • Application: Printing a structured document.

    • Verbatim Pre-order Code: python def preOrder(self, start): # start at root -> left -> right if start: print(start._element) self.preOrder(start._left) self.preOrder(start._right)     

  • Inorder Traversal:

    • Logic: Reading nodes from left to right. It traverses the left subtree, visits the node itself, and then follows the right subtree.

    • Process: Go as far left as possible, print, move up, print, and then attempt to move right.

    • Verbatim Inorder Code: python def inOrder(self, start): # start left -> root -> right if start: self.inOrder(start._left) print(start._element) self.inOrder(start._right)     

  • Postorder Traversal:

    • Logic: A node is visited only after its descendants have been processed (opposite of pre-order).

    • Process: Child first, then root.

    • Path Example: 9, 3, 1, 7, 2, 4, 5, 6, 8.

    • Application: File system size calculation (e.g., cs16/homeworks/ totaling 1K for todo.txt, 10K for DDR.java, 25K for Stocks.java, 3K for h1c.doc, 2K for h1nc.doc, 20K for Robot.java).

    • Verbatim Postorder Code: python def postOrder(self, start): # start left -> right -> root if start: self.postOrder(start._left) self.postOrder(start._right) print(start._element)     

Breadth-First Traversal Algorithm

  • Methodology: Nodes are visited level by level (Level 0, Level 1, Level 2…), moving from left to right within each level.

  • Structural Requirement: Recursion cannot be used because it naturally leads deeper into the tree rather than across levels. Instead, a queue data structure is required to store child nodes.

  • Algorithm Logic:

    1. Initialize Queue q to the root of the tree.

    2. While q is not empty:

    • Dequeue the oldest element.

    • Print the element.

    • If the left node is not null, enqueue it.

    • If the right node is not null, enqueue it.

  • Verbatim Breadth-First Code:

  def breadthFirst(self):
      # level by level
      q = ArrayQueue()
      q.enqueue(self._root)
      while not q.is_empty():
          node = q.dequeue()
          print(node._element)
          if node._left is not None:
              q.enqueue(node._left)
          if node._right is not None:
              q.enqueue(node._right)
  ```

# Calculating the Size of a Tree
- Logic: Similar to traversal, calculating size uses recursion to count every node.
- Sizing Algorithm:
  - If the current node is `None`, return 0.
  - Otherwise, return 1+printSize(left node)+printSize(right node)1 + \text{printSize(left node)} + \text{printSize(right node)}.
- Verbatim Size Code:

python def printSize(self, start): if start: return (1 + self.printSize(start._left) + self.printSize(start._right)) else: return 0   ```

Arithmetic Expression Trees

  • Definition: Binary trees designed to represent arithmetic expressions. This structure removes the need for parentheses.

  • Component Mapping:

    • Internal Nodes: Store operators (e.g., ,+,,×,/, +, -, \times, /).

    • External Nodes (Leaves): Store operands (e.g., constants or variables).

  • Example Expression: (2×(a1)+(3×b))(2 \times (a - 1) + (3 \times b))

  • Representation Logic: Use inorder traversal to retrieve a familiar infix representation.

  • Printing with Parentheses (Specialized Inorder):

    • Print "(" before traversing the left subtree.

    • Print the operand or operator when visiting the node.

    • Print ")" after traversing the right subtree.

  • Arithmetic Tree Algorithm: python Algorithm printExpression(v): if v has a left child: print("(") inOrder(left(v)) print(v.element()) if v has a right child: inOrder(right(v)) print(")")