Trees 1: Theory, Models, Generic Heap Algorithms, Priority Queues Andy Wang Data Structures, Algorithms, and Generic Programming Trees 1: Overview General trees—theory and terminology Tree traversals Binary trees Vector implementation of binary trees Partially ordered trees (POT) Heap algorithms Heapsort Priority queue Theory and Terminology Definition: A tree is a connected graph with no cycles Consequences: Between any two vertices, there is exactly one unique path 8 3 4 1 9 10 7 2 5 6 A Tree? 11 12 A Tree? Nope 5 9 10 6 7 8 2 3 4 1 11 12 A Tree? 5 9 10 6 7 8 2 3 4 1 11 12 A Tree? Yup 5 9 10 6 7 8 2 3 4 1 11 12 Theory and Terminology Definition: A rooted tree is a graph G such that: G is connected G has no cycles G has exactly one vertex called the root of the tree Theory and Terminology Consequences The depth of a vertex v is the length of the unique path from root to v G can be arranged so that the root is at the top, its neighboring vertices are vertices of depth 1, and so on… The set of all vertices of depth k is called level k of the tree A Rooted Tree depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Definition: A descending path in a rooted tree is a path, whose edges go from a vertex to a deeper vertex depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Consequences: A unique path from the root to any vertex is a descending path The length of this path is the depth of the vertex depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Definition: If there is a descending path from v1 to v2, v1 is an ancestor of v2, and v2 is a descendant of v1. Theory and Terminology Suppose v is a vertex of depth k: Any vertex that is adjacent to v must have depth k - 1 or k + 1. depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Suppose v is a vertex of depth k: Vertices adjacent to v of depth k + 1 are called children of v. depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Suppose v is a vertex of depth k: If k > 0, there is exactly one vertex of depth k – 1 that is adjacent to v in the graph. This vertex is called the parent of v. depth = 0 root 1 depth = 1 depth = 2 depth = 3 5 2 3 4 6 7 8 9 10 11 12 Theory and Terminology Definitions A vertex with no children is called a leaf depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Theory and Terminology Definitions The height of a tree is the maximum depth of its vertices depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 height depth = 2 depth = 3 5 11 12 Theory and Terminology Definitions The root is the only vertex of depth 0. The root has no parent. depth = 0 root 1 depth = 1 2 3 4 6 7 8 9 10 depth = 2 depth = 3 5 11 12 Tree Traversals Definition: A traversal is the process for “visiting” all of the vertices in a tree Often defined recursively Each kind corresponds to an iterator type Iterators are implemented nonrecursively Preorder Traversal Visit vertex, then visit child vertices (recursive definition) Depth-first search Begin at root Visit vertex on arrival Implementation may be recursive, stack-based, or nested loop Preorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Preorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Postorder Traversal Visit child vertices, then visit vertex (recursive definition) Depth-first search Begin at root Visit vertex on departure Implementation may be recursive, stack-based, or nested loop Postorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Postorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Postorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Postorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Levelorder Traversal Visit all vertices in level, starting with level 0 and increasing Breadth-first search Begin at root Visit vertex on departure Only practical implementation is queue-based Levelorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Levelorder Traversal 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 5 5 root 1 2 3 4 6 7 8 root 1 2 3 4 6 7 8 Tree Traversals Preoder: depth-first search (possibly stack-based), visit on arrival Postorder: depth-first search (possibly stack-based), visit on departure Levelorder: breadth-first search (queue-based), visit on departure Binary Trees Definition: A binary tree is a rooted tree in which no vertex has more than two children root 4 1 2 3 5 6 7 Binary Trees Definition: A binary tree is complete iff every layer but the bottom is fully populated with vertices. root 4 1 2 3 5 6 7 Binary Trees A complete binary tree with n vertices and high H satisfies: 2H <= n < 2H + 1 22 <= 7 < 22 + 1 root 4 1 2 3 5 6 7 Binary Trees A complete binary tree with n vertices and high H satisfies: 2H <= n < 2H + 1 H <= lg n < H + 1 H = floor(lg n) Binary Trees Theorem: In a complete binary tree with n vertices and height H 2H <= n < 2H + 1 Binary Trees Proof: For level k, there are 2k vertices Total number of vertices: n = 20 + 21 + …2k n = 1 + 21 + 22 +…2k n = 1 + 2(1 + 21 +…2k-1) n = 1 + 2(n - 2k) n = 1 + 2n – 2k + 1 n = 2k + 1 - 1 Binary Trees Let k = H number of vertices for height H = 2H + 1 – 1 number of vertices for height H < 2H + 1 Let k = H – 1 number of vertices for height H - 1 = 2H – 1 number of vertices for height H >= 2H 2H <= n < 2H + 1 Binary Tree Traversals Inorder traversal Definition: left child, visit, right child (recursive) Algorithm: depth-first search (visit between children) Inorder Traversal root 4 root 2 3 5 6 root 4 1 7 4 1 2 3 5 6 root 2 3 5 6 7 4 1 7 1 2 3 5 6 7 Inorder Traversal root 4 root 2 3 5 6 root 4 1 7 4 1 2 3 5 6 root 2 3 5 6 7 4 1 7 1 2 3 5 6 7 Inorder Traversal root 4 root 2 3 5 6 root 4 1 7 4 1 2 3 5 6 root 2 3 5 6 7 4 1 7 1 2 3 5 6 7 Inorder Traversal root 4 1 root 2 3 5 6 7 4 1 2 3 5 6 7 Binary Tree Traversals Other traversal apply to binary case: Preorder traversal vertex, left subtree, right subtree Inorder traversal left subtree, vertex, right subtree Postorder traversal left subtree, right subtree, vertex Levelorder traversal vertex, left children, right children Vector Representation of Complete Binary Tree Tree data Vector elements carry data Tree structure Vector indices carry tree structure Index order = levelorder Tree structure is implicit Uses integer arithmetic for tree navigation Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] root ll 0 l r lr rl rr Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 0 1 2 3 4 5 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 0 l 2 3 4 5 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 2 0 l r 3 4 5 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 2 3 0 l r ll 4 5 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 2 3 4 0 l r ll lr 5 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 2 3 4 5 0 l r ll lr rl 6 Vector Representation of Complete Binary Tree Tree navigation Parent of v[k] = v[(k – 1)/2] Left child of v[k] = v[2*k + 1] Right child of v[k] = v[2*k + 2] 0 1 2 3 4 5 6 0 l r ll lr rl rr Partially Ordered Trees Definition: A partially ordered tree is a tree T such that: There is an order relation >= defined for the vertices of T For any vertex p and any child c of p, p >= c Partially Ordered Trees Consequences: The largest element in a partially ordered tree (POT) is the root No conclusion can be drawn about the order of children Heaps Definition: A heap is a partially ordered complete (almost) binary tree. The tree is completely filled on all levels except possibly the lowest. root 3 1 0 4 2 Heaps Consequences: The largest element in a heap is the root A heap can be stored using the vector implementation of binary tree Heap algorithms: Push Heap Pop Heap The Push Heap Algorithm Add new data at next leaf Repair upward Repeat Locate parent if POT not satisfied swap else stop Until POT The Push Heap Algorithm Add new data at next leaf 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 5 4 3 The Push Heap Algorithm Add new data at next leaf 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 5 4 3 8 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 5 4 3 8 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 5 4 3 8 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 8 4 3 5 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 8 4 3 5 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 8 4 3 5 The Push Heap Algorithm Repeat Locate parent of v[k] = v[(k – 1)/2] if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 8 6 7 4 3 5 The Pop Heap Algorithm Copy last leaf to root Remove last leaf Repeat find the larger child if POT not satisfied swap else stop Until POT The Pop Heap Algorithm Copy last leaf to root 0 1 2 3 4 5 6 0 l r ll lr rl rr 8 6 7 4 3 5 The Pop Heap Algorithm Copy last leaf to root 0 1 2 3 4 5 6 0 l r ll lr rl rr 5 6 7 4 3 5 The Pop Heap Algorithm Remove last leaf 0 1 2 3 4 5 6 0 l r ll lr rl rr 5 6 7 4 3 The Pop Heap Algorithm Repeat find the larger child if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 5 6 7 4 3 The Pop Heap Algorithm Repeat find the larger child if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 5 6 7 4 3 The Pop Heap Algorithm Repeat find the larger child if POT not satisfied swap else stop 0 1 2 3 4 5 6 0 l r ll lr rl rr 7 6 5 4 3 Generic Heap Algorithms Apply to ranges Specified by random access iterators Current support Arrays TVector<T> TDeque<T> Source code file: gheap.h Test code file: fgss.cpp Priority Queues Element type with priority typename T t Predicate class P p Associative queue operations void Push(t) void Pop() T& Front() Priority Queues Associative property Priority value determined by p Push(t) inserts t, increases size by 1 Pop() removes element with highest priority value, decreases size by 1 Front() returns element with highest priority value, no state change The Priority Queue Generic Adaptor template <typename T, class C, class P> class CPriorityQueue { C c; P LessThan; public: typedef typename C::value_type value_type; int Empty() const { return c.Empty(); } unsigned int Size() const { return c.Size(); } void Clear() { c.Clear(); } CPriorityQueue& operator=(const CPriorityQueue& q) { if (this != &q) { c = q.c; LessThan = q.LessThan; } return *this; } The Priority Queue Generic Adaptor void Display(ostream& os, char ofc = ‘\0’) const { c.Display(os, ofc); } void Push(const value_type& t) { c.PushBack(t); g_push_heap(c.Begin(), c.End(), LessThan); } void Pop() { if (Empty()) { cerr << “error” << endl; exit(EXIT_FALIURE); } g_pop_heap(c.Begin(), c.End(), LessThan); c.PopBack(); } };