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 is calculated as .
Example: If a tree has 4 nodes (), 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 , where 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:
Initialize Queue
qto the root of the tree.While
qis 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 .
- 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., ).
External Nodes (Leaves): Store operands (e.g., constants or variables).
Example Expression:
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(")")