Directed, Rooted Tree Binary Trees Chapter 5 CPTR 318 Every non-empty directed, rooted tree has A unique element called root One or more elements called leaves Every element except root has a unique parent All elements have zero or more children A leaf has no children A non-leaf has one or more children We will deal only with directed, rooted trees 1 2 Trees A tree with n 1 nodes contains n 1 edges Can you prove this? Every node except root has a parent An edge connects a node to its parent Terminology Path A sequence of nodes n 0, n 1, n 2,, n k such that n i is the parent of n i+1 for all 1 i k Path length The number of edges on the path; n 1 In a tree there is exactly one path from the root to a given node Node depth Depth of n i is the length of the path from the root to n i Node height Length of longest path to a leaf Tree height Depth of the deepest node + 1 Possible Implementation template <typename T> struct Node T data; std::list<node *> children; ; Binary Trees Each node may have 0, 1, or 2 children What is the minimum height of a binary tree with n nodes? What is the maximum height of a binary tree with n nodes? 1
Binary Search Tree Binary Tree Traversals For all nodes in the binary tree T: All the nodes in the left subtree of T s root are less than T s root node All the nodes in the right subtree of T s root are greater than T s root node template <typename T> struct Node T data; Node *left; Node *right; ; Preorder: node, preorder left subtree, preorder right subtree Inorder: inorder left subtree, node, inorder right subtree Postorder: postorder left subtree, postorder right subtree, node Easily expressed recursively Reconstruction from traversals Can you deduce the structure of a binary tree from one of its traversals? Use two traversals Balancing Problem Binary trees work best when balanced How can we keep a tree balanced? Priority Queues We would like to insert (enqueue) an element with a given priority We would like to serve (dequeue) the element with the highest priority Use a standard queue? What is the time to enqueue? O(1) What is the time to dequeue? O(n) Insertions cheap, deletions more expensive 11 12 2
Keep a sorted queue? Complete Binary Tree What is the time to enqueue? O(n) What is the time to dequeue? O(1) Insertions more expensive, deletions cheap A binary tree (not a binary search tree) Completely filled as much as possible, given its size Only possible incomplete level is the last level Last level is filled left to right 13 14 Easily mapped to an array Navigating the Array Version left_child(i) = 2i + 1 right_child(i) = 2i + 2 parent(i) = i 1 2 A B C D E F G H I J 0 1 2 3 4 5 6 7 8 9 10 11 12 A B C D E F G H I J 0 1 2 3 4 5 6 7 8 9 10 11 12 16 Navigating the Array Version Advantage of Array Representation? left_child(i) = 2i + 1 right_child(i) = 2i + 2 parent(i) = i 1 2 A B C D E F G H I J 0 1 2 3 4 5 6 7 8 9 10 11 12 Saves space no links required 17 18 3
Heap Order Property Smallest (or largest) element is at the root value(parent(i)) value(i), for all i root parent(root) is undefined Heap Implementation template <typename T, typename Comp> class Heap private: T* heap; // Pointer to the heap array int maxsize; // Maximum size of the heap int n; // Number of elements now in the heap // Methods omitted //... ; 19 22 23 24 25 4
Insertion (in book) heap[curr] = elem; // Start at end of heap swap(heap, curr, parent(curr)); Page 180 26 27 Insertion Insertion heap[curr] = elem; // Start at end of heap swap(heap, curr, parent(curr)); Page 180 swap(heap, curr, parent(curr)); heap[curr] = elem; // Place new element Page 180 28 Insertion Insertion swap(heap, curr, parent(curr)); heap[curr] = elem; // Place new element Page 180 heap[curr] = heap[parent(curr)]; heap[curr] = elem; // Place new element Page 180 5
Insertion (improved) Insertion Time complexity heap[curr] = heap[parent(curr)]; heap[curr] = elem; // Place new element Worst case O(log n) On average much better 2.607 comparisons O(1) 35 36 37 38 CPTR 314 6
39 CPTR 314 40 // Remove first value T removefirst() Assert (n > 0, "Heap is empty"); swap(heap, 0, --n); // Swap first with last element if ( n!= 0 ) siftdown(0); // Sift down new root element return heap[n]; // Return deleted value Page 181 Siftdown (in book) // Helper function to put element in its correct place void siftdown(int pos) while (!isleaf(pos)) // Stop if pos is a leaf int j = leftchild(pos), rc = rightchild(pos); if ((rc < n) && Comp::prior(heap[rc], heap[j])) j = rc; // Set j to greater child s value if (Comp::prior(heap[pos], heap[j])) return; // Done swap(heap, pos, j); pos = j; // Move down Page 180 Siftdown (improved) // Helper function to put element in its correct place void siftdown(int pos) T temp = heap[pos]; while (!isleaf(pos)) // Stop if pos is a leaf int j = leftchild(pos), rc = rightchild(pos); if ((rc < n) && Comp::prior(heap[rc], heap[j])) j = rc; // Set j to greater child s value if (Comp::prior(temp, heap[j])) break; // Done heap[pos] = heap[j]; pos = j; // Move down heap[pos] = temp; Time Complexity Worst case O(log n) Average case O(log n) 7
Decrease Key Build Heap If the value of an element in a min-heap decreases (or increases in a max-heap), the value may need to move up (or down) to maintain the heap property For example, circumstances may result in a lower priority job being elevated to a higher priority Several well-known graph algorithms make use of this operation decrease_key is worst case O(log n), but many times in practice an element usually moves only a small distance due to a small change in value Makes a heap out of an array of unordered elements Insert n elements Each insert is O(log n) worst case time, O(1) average time O(n log n) worst case, O(n) average case Huffman Trees Fixed-width character encoding vs. variablewidth character encoding 8