Analysis of Algorithms CS 477/677 Instructor: Monica Nicolescu The Heap Data Structure • Def: A heap is a nearly complete binary tree with the following two properties: – Structural property: all levels are full, except possibly the last one, which is filled from left to right – Order (heap) property: for any node x Parent(x) ≥ x 8 7 5 4 2 It doesn’t matter that 4 in level 1 is smaller than 5 in level 2 Heap CS 477/677 2 Array Representation of Heaps • A heap can be stored as an array A. – Root of tree is A[1] – Left child of A[i] = A[2i] – Right child of A[i] = A[2i + 1] – Parent of A[i] = A[ i/2 ] – Heapsize[A] ≤ length[A] • The elements in the subarray A[(n/2+1) .. n] are leaves • The root is the maximum element of the heap A heap is a binary tree that is filled in order CS 477/677 3 Maintaining the Heap Property • Suppose a node is smaller than a child – Left and Right subtrees of i are max-heaps • Invariant: – the heap condition is violated only at that node • To eliminate the violation: – Exchange with larger child – Move down the tree – Continue until node is not smaller than children CS 477/677 4 Building a Heap • Convert an array A[1 … n] into a max-heap (n = length[A]) • The elements in the subarray A[(n/2+1) .. n] are leaves • Apply MAX-HEAPIFY on elements between 1 and n/2 1 4 2 3 1 3 4 8 2 14 A: 4 1 3 2 5 6 7 16 9 9 10 8 7 16 9 10 14 CS 477/677 10 8 7 5 Heapsort • Goal: – Sort an array using heap representations • Idea: – Build a max-heap from the array – Swap the root (the maximum element) with the last element in the array – “Discard” this last node by decreasing the heap size – Call MAX-HEAPIFY on the new root – Repeat this process until only one node remains CS 477/677 6 Alg: HEAPSORT(A) 1. BUILD-MAX-HEAP(A) O(n) 2. for i ← length[A] downto 2 3. 4. • n-1 times do exchange A[1] ↔ A[i] MAX-HEAPIFY(A, 1, i - 1) O(lgn) Running time: O(nlgn) CS 477/677 7 Example: MAX-HEAPIFY(A, 1, 4) A=[7, 4, 3, 1, 2] MAX-HEAPIFY(A, 1, 3) MAX-HEAPIFY(A, 1, 2) MAX-HEAPIFY(A, 1, 1) CS 477/677 8 HEAP-MAXIMUM Goal: – Return the largest element of the heap Alg: HEAP-MAXIMUM(A) 1. Running time: O(1) return A[1] Heap A: Heap-Maximum(A) returns 7 CS 477/677 9 HEAP-EXTRACT-MAX Goal: – Extract the largest element of the heap (i.e., return the max value and also remove that element from the heap Idea: – Exchange the root element with the last – Decrease the size of the heap by 1 element – Call MAX-HEAPIFY on the new root, on a heap of size n-1 Heap A: Root is the largest element CS 477/677 10 HEAP-EXTRACT-MAX Alg: HEAP-EXTRACT-MAX(A, n) 1. if n < 1 2. then error “heap underflow” 3. max ← A[1] 4. A[1] ← A[n] 5. MAX-HEAPIFY(A, 1, n-1) 6. return max remakes heap Running time: O(lgn) CS 477/677 11 Example: HEAP-EXTRACT-MAX 16 14 7 4 max = 16 10 8 2 1 9 14 3 10 8 1 2 7 9 3 4 Heap size decreased with 1 14 Call MAX-HEAPIFY(A, 1, n-1) 8 4 2 10 7 9 3 1 CS 477/677 12 HEAP-INCREASE-KEY • Goal: – Increases the key of an element i in the heap • Idea: – Increment the key of A[i] to its new value – If the max-heap property does not hold anymore: traverse a path toward the root to find the proper place for the newly increased key 16 14 Key [i] ← 15 2 8 i 4 10 7 9 3 1 CS 477/677 13 HEAP-INCREASE-KEY Alg: HEAP-INCREASE-KEY(A, i, key) 1. 2. 3. 4. 5. 6. • if key < A[i] then error “new key is smaller than current key” A[i] ← key 16 while i > 1 and A[PARENT(i)] < A[i] do exchange A[i] ↔ A[PARENT(i)] 14 i ← PARENT(i) 2 Running time: O(lgn) 8 i 4 7 10 9 3 1 Key [i] ← 15 CS 477/677 14 Example: HEAP-INCREASE-KEY 16 14 2 8 i 4 16 10 7 9 14 3 1 2 10 8 i 7 15 1 9 3 Key [i ] ← 15 16 i 15 2 14 i 15 10 7 8 16 9 3 10 14 1 2 CS 477/677 7 8 9 3 1 15 MAX-HEAP-INSERT • Goal: 16 – Inserts a new element into a maxheap 14 10 8 • Idea: – Expand the max-heap with a new element whose key is - – Calls HEAP-INCREASE-KEY to set the key of the new node to its correct value and maintain the max-heap property CS 477/677 2 7 4 1 9 3 - 16 14 10 8 2 7 4 1 9 3 15 16 MAX-HEAP-INSERT 16 Alg: MAX-HEAP-INSERT(A, key, n) 14 1. heap-size[A] ← n + 1 8 2 2. A[n + 1] ← - 10 7 4 1 9 3 - 3. HEAP-INCREASE-KEY(A, n + 1, key) Running time: O(lgn) CS 477/677 17 Example: MAX-HEAP-INSERT Insert value 15: - Start by inserting - Increase the key to 15 Call HEAP-INCREASE-KEY on A[11] = 15 16 16 14 8 2 7 4 14 10 1 9 8 3 2 - 10 7 4 1 9 3 15 The restored heap containing the newly added element 16 16 14 8 2 15 9 4 15 10 1 7 10 8 3 2 CS 477/677 14 9 4 1 3 7 18 Summary • We can perform the following operations on heaps: – MAX-HEAPIFY O(lgn) – BUILD-MAX-HEAP O(n) – HEAP-SORT O(nlgn) – MAX-HEAP-INSERT O(lgn) – HEAP-EXTRACT-MAX O(lgn) – HEAP-INCREASE-KEY O(lgn) – HEAP-MAXIMUM O(1) CS 477/677 19 The Search Problem • Find items with keys matching a given search key Applications: • Keeping track of customer account information at a bank – Search through records to check balances and perform transactions • Keep track of reservations on flights – Search to find empty seats, cancel/modify reservations • Search engine – Looks for all documents containing a given word CS 477/677 20 Symbol Tables (Dictionaries) • Dictionary = data structure that supports two basic operations: insert a new item and return an item with a given key • Queries: return information about the set – Search (S, k) – Minimum (S), Maximum (S) – Successor (S, x), Predecessor (S, x) • Modifying operations: change the set – Insert (S, k) – Delete (S, k) CS 477/677 21 Implementations of Symbol Tables • Key-indexed-array – Key values are distinct, small numbers – Store the items in an array, indexed by keys • Ordered/unordered arrays • Ordered/unordered linked lists Insert key-indexed array ordered array ordered list unordered array unordered list 1 N N 1 1 CS 477/677 Search 1 N N N N 22 Binary Search Trees • Support many dynamic set operations – SEARCH, MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR, INSERT • Running time of basic operations on binary search trees – On average: (lgn) • The expected height of the tree is lgn – In the worst case: (n) • The tree is a linear chain of n nodes CS 477/677 23 Binary Search Trees • Tree representation: – A linked data structure in which each node is an object • Node representation: – – – – – Key field Satellite data Left: pointer to left child Right: pointer to right child p: pointer to parent (p [root [T]] = NIL) L parent key data Left child R Right child • Satisfies the binary-search-tree property CS 477/677 24 Binary Search Tree Example • Binary search tree property: – If y is in left subtree of x, then key [y] ≤ key [x] – If y is in right subtree of x, then key [y] ≥ key [x] CS 477/677 5 3 2 7 5 9 25 Traversing a Binary Search Tree • Inorder tree walk: – Prints the keys of a binary tree in sorted order – Root is printed between the values of its left and right subtrees: left, root, right • Preorder tree walk: – root printed first: root, left, right • Postorder tree walk: left, right, root – root printed last Inorder: 2 3 5 5 7 9 5 3 2 Preorder: 5 3 2 5 7 9 7 5 9 Postorder: 2 5 3 9 7 5 CS 477/677 26 Traversing a Binary Search Tree Alg: INORDER-TREE-WALK(x) 1. if x NIL 2. then INORDER-TREE-WALK ( left [x] ) 3. print key [x] 4. INORDER-TREE-WALK ( right [x] ) • E.g.: 5 3 2 Output: 2 3 5 5 7 9 7 5 9 • Running time: – (n), where n is the size of the tree rooted at x CS 477/677 27 Searching for a Key • Given a pointer to the root of a tree and a key k: – Return a pointer to a node with key k if one exists – • 5 3 Otherwise return NIL 2 7 4 9 Idea – Starting at the root: trace down a path by comparing k with the key of the current node: • If the keys are equal: we have found the key • If k < key[x] search in the left subtree of x • If k > key[x] search in the right subtree of x CS 477/677 28 Searching for a Key Alg: TREE-SEARCH(x, k) 5 1. if x = NIL or k = key [x] 3 7 2 4 9 2. then return x 3. if k < key [x] 4. then return TREE-SEARCH(left [x], k ) 5. else return TREE-SEARCH(right [x], k ) Running Time: O (h), h – the height of the tree CS 477/677 29 Example: TREE-SEARCH 15 • Search for key 13: 6 3 2 – 15 6 7 13 18 7 17 4 20 13 9 CS 477/677 30 Iterative Tree Search Alg: ITERATIVE-TREE-SEARCH(x, k) 1. while x NIL and k key [x] 2. do if k < key [x] 3. then x left [x] 4. else x right [x] 5. return x CS 477/677 31 Finding the Minimum in a Binary Search Tree • Goal: find the minimum value in a BST – Following left child pointers from the root, until a NIL is encountered 15 Alg: TREE-MINIMUM(x) 1. while left [x] NIL 2. do x ← left [x] 3. return x 6 3 2 18 7 17 4 20 13 9 Minimum = 2 Running time: O(h), h – height of tree CS 477/677 32 Finding the Maximum in a Binary Search Tree • Goal: find the maximum value in a BST – Following right child pointers from the root, until a NIL is encountered 15 Alg: TREE-MAXIMUM(x) 1. while right [x] NIL 2. do x ← right [x] 3. return x 6 3 2 18 7 17 4 20 13 9 Maximum = 20 • Running time: O(h), h – height of tree CS 477/677 33 Successor Def: successor (x ) = y, such that key [y] is the smallest key > key [x] • E.g.: successor (15) = 17 6 successor (13) = 15 3 successor (9) = 13 2 • Case 1: right (x) is non empty 15 18 7 17 4 20 13 9 – successor (x ) = the minimum in right (x) • Case 2: right (x) is empty – go up the tree until the current node is a left child: successor (x ) is the parent of the current node – if you cannot go further (and you reached the root): x is the largest element CS 477/677 34 Finding the Successor Alg: TREE-SUCCESSOR(x) 1. 2. 3. 4. 5. 6. 7. if right [x] NIL then return TREE-MINIMUM(right [x]) y ← p[x] while y NIL and x = right [y] 6 do x ← y 3 y ← p[y] 2 4 return y 15 y 7 17 13 18 20 x 9 Running time: O (h), h – height of the tree CS 477/677 35 Predecessor Def: predecessor (x ) = y, such that key [y] is the biggest key < key [x] 15 • E.g.: predecessor (15) = 13 predecessor (9) = 7 6 predecessor (13) = 9 3 • Case 1: left (x) is non empty 2 18 7 17 4 – predecessor (x ) = the maximum in left (x) 20 13 9 • Case 2: left (x) is empty – go up the tree until the current node is a right child: predecessor (x ) is the parent of the current node – if you cannot go further (and you reached the root): x is the smallest element CS 477/677 36 Insertion • Goal: – Insert value v into a binary search tree • Idea: – If key [x] < v move to the right child of x, Insert value 13 else move to the left child of x 12 – When x is NIL, we found the correct position – If v < key [y] insert the new node as y’s left child else insert it as y’s right child 5 2 1 18 9 15 3 13 19 17 – Begining at the root, go down the tree and maintain: • Pointer x : traces the downward path (current node) • Pointer y : parent of x (“trailing pointer” ) CS 477/677 37 Example: TREE-INSERT Insert 13: x, y=NIL 12 y 12 x 5 2 1 18 9 15 3 5 19 18 2 1 17 9 15 3 17 12 12 5 2 1 x y 18 9 15 3 19 5 2 19 1 17 18 9 15 3 13 19 17 x = NIL y = 15 CS 477/677 38 Alg: TREE-INSERT(T, z) 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. y ← NIL x ← root [T] while x ≠ NIL do y ← x if key [z] < key [x] then x ← left [x] else x ← right [x] p[z] ← y if y = NIL then root [T] ← z else if key [z] < key [y] then left [y] ← z else right [y] ← z CS 477/677 12 5 2 1 18 9 15 3 13 19 17 Tree T was empty Running time: O(h) 39 Readings • Chapter 6 • Chapter 12 CS 477/677 40