Divide-and-Conquer Algorithms Part Two

Similar documents
Priority queues implemented via heaps

Review Of Topics. Review: Induction

MA008/MIIZ01 Design and Analysis of Algorithms Lecture Notes 3

2.2 Asymptotic Order of Growth. definitions and notation (2.2) examples (2.4) properties (2.2)

IS 709/809: Computational Methods in IS Research Fall Exam Review

b + O(n d ) where a 1, b > 1, then O(n d log n) if a = b d d ) if a < b d O(n log b a ) if a > b d

Computational Complexity

Analysis of Algorithms I: Asymptotic Notation, Induction, and MergeSort

CS Data Structures and Algorithm Analysis

COMP 355 Advanced Algorithms

When we use asymptotic notation within an expression, the asymptotic notation is shorthand for an unspecified function satisfying the relation:

COMP 355 Advanced Algorithms Algorithm Design Review: Mathematical Background

CS 4407 Algorithms Lecture 2: Iterative and Divide and Conquer Algorithms

Sorting Algorithms. We have already seen: Selection-sort Insertion-sort Heap-sort. We will see: Bubble-sort Merge-sort Quick-sort

More Asymptotic Analysis Spring 2018 Discussion 8: March 6, 2018

data structures and algorithms lecture 2

2. ALGORITHM ANALYSIS

Matching Residents to Hospitals

Algorithm runtime analysis and computational tractability

Algorithms, Design and Analysis. Order of growth. Table 2.1. Big-oh. Asymptotic growth rate. Types of formulas for basic operation count

Assignment 5: Solutions

CS173 Running Time and Big-O. Tandy Warnow

Grade 11/12 Math Circles Fall Nov. 5 Recurrences, Part 2

Data Structures and Algorithms

CS 4407 Algorithms Lecture 3: Iterative and Divide and Conquer Algorithms

CSCE 750 Final Exam Answer Key Wednesday December 7, 2005

i=1 i B[i] B[i] + A[i, j]; c n for j n downto i + 1 do c n i=1 (n i) C[i] C[i] + A[i, j]; c n

CS361 Homework #3 Solutions

Divide and Conquer. CSE21 Winter 2017, Day 9 (B00), Day 6 (A00) January 30,

Divide and Conquer. Andreas Klappenecker

Asymptotic Analysis and Recurrences

1 Terminology and setup

Problem 5. Use mathematical induction to show that when n is an exact power of two, the solution of the recurrence

CPS 616 DIVIDE-AND-CONQUER 6-1

Insertion Sort. We take the first element: 34 is sorted

Asymptotic Analysis. Slides by Carl Kingsford. Jan. 27, AD Chapter 2

When we use asymptotic notation within an expression, the asymptotic notation is shorthand for an unspecified function satisfying the relation:

Data Structures and Algorithms Chapter 3

5. DIVIDE AND CONQUER I

Analysis of Algorithms

COMP 382: Reasoning about algorithms

In-Class Soln 1. CS 361, Lecture 4. Today s Outline. In-Class Soln 2

Divide and Conquer. Recurrence Relations

Copyright 2000, Kevin Wayne 1

CSE101: Design and Analysis of Algorithms. Ragesh Jaiswal, CSE, UCSD

Analysis of Algorithms - Midterm (Solutions)

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Asymptotic Analysis, recurrences Date: 9/7/17

Omega notation. Transitivity etc.

Concrete models and tight upper/lower bounds

University of New Mexico Department of Computer Science. Midterm Examination. CS 361 Data Structures and Algorithms Spring, 2003

CS 310 Advanced Data Structures and Algorithms

Divide and Conquer CPE 349. Theresa Migler-VonDollen

Analysis of Algorithm Efficiency. Dr. Yingwu Zhu

5. DIVIDE AND CONQUER I

Searching. Sorting. Lambdas

CS 344 Design and Analysis of Algorithms. Tarek El-Gaaly Course website:

Lecture 1: Asymptotics, Recurrences, Elementary Sorting

How many hours would you estimate that you spent on this assignment?

Disjoint-Set Forests

Midterm Exam. CS 3110: Design and Analysis of Algorithms. June 20, Group 1 Group 2 Group 3

CS 577 Introduction to Algorithms: Strassen s Algorithm and the Master Theorem

Data Structures and Algorithms Chapter 3

Sorting. Chapter 11. CSE 2011 Prof. J. Elder Last Updated: :11 AM

Divide and Conquer. Andreas Klappenecker. [based on slides by Prof. Welch]

COMP Analysis of Algorithms & Data Structures

Copyright 2000, Kevin Wayne 1

Complexity Theory Part I

Mergesort and Recurrences (CLRS 2.3, 4.4)

Lecture 2. More Algorithm Analysis, Math and MCSS By: Sarah Buchanan

Asymptotic Analysis 1

Analysis of Algorithms

Quiz 1 Solutions. Problem 2. Asymptotics & Recurrences [20 points] (3 parts)

LECTURE NOTES ON DESIGN AND ANALYSIS OF ALGORITHMS

Algorithms Test 1. Question 1. (10 points) for (i = 1; i <= n; i++) { j = 1; while (j < n) {

Asymptotic Analysis Cont'd

Algorithms And Programming I. Lecture 5 Quicksort

Data Structures in Java

COMP Analysis of Algorithms & Data Structures

Part IA Algorithms Notes

Asymptotic Analysis. Thomas A. Anastasio. January 7, 2004

Fundamental Algorithms

CS 161 Summer 2009 Homework #2 Sample Solutions

Week 5: Quicksort, Lower bound, Greedy

Divide and Conquer Algorithms. CSE 101: Design and Analysis of Algorithms Lecture 14

Algorithms. Quicksort. Slide credit: David Luebke (Virginia)

Divide-Conquer-Glue. Divide-Conquer-Glue Algorithm Strategy. Skyline Problem as an Example of Divide-Conquer-Glue

Heaps and Priority Queues

Notes for Recitation 14

Ch01. Analysis of Algorithms

Lecture 14: Nov. 11 & 13

ENS Lyon Camp. Day 2. Basic group. Cartesian Tree. 26 October

Chapter 5 Data Structures Algorithm Theory WS 2017/18 Fabian Kuhn

An analogy from Calculus: limits

CSC236 Week 3. Larry Zhang

Algorithm Design and Analysis

Divide and Conquer Algorithms

Reductions, Recursion and Divide and Conquer

Big O 2/14/13. Administrative. Does it terminate? David Kauchak cs302 Spring 2013

Divide-and-conquer: Order Statistics. Curs: Fall 2017

AC64/AT64/ AC115/AT115 DESIGN & ANALYSIS OF ALGORITHMS

Transcription:

Divide-and-Conquer Algorithms Part Two

Recap from Last Time

Divide-and-Conquer Algorithms A divide-and-conquer algorithm is one that works as follows: (Divide) Split the input apart into multiple smaller pieces, then recursively invoke the algorithm on those pieces. (Conquer) Combine those solutions back together to form the overall answer. Can be analyzed using recurrence relations.

Two Important Recurrences T(0) T(0) = Θ(1) T(1) T(1) = Θ(1) T(n) T(n) = T( n T( n // 2 ) 2 ) + T( n T( n // 2 ) 2 ) + Θ(n) Solves to O(n log n) T(0) T(0) = Θ(1) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + Θ(1) Solves to O(log n)

Outline for Today More Recurrences Other divide-and-conquer relations. Algorithmic Lower Bounds Showing that certain problems cannot be solved within certain limits. Binary Heaps A fast data structure for retrieving elements in sorted order.

Another Algorithm: Maximizing Unimodal Arrays

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality An An array array is is called unimodal iff iff it it can can be be split split into into an an increasing sequence followed by by a decreasing sequence. 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality An An array array is is called unimodal iff iff it it can can be be split split into into an an increasing sequence followed by by a decreasing sequence. 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality 1 3 4 5 7 8 10 12 13 14 10 9 6 2

procedure unimodalmax(list A, A, int int low, low, int int high): high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] < A[mid A[mid + 1] 1] return unimodalmax(a, mid mid + 1, 1, high) high) else: else: return unimodalmax(a, low, low, mid mid + 1) 1)

procedure unimodalmax(list A, A, int int low, low, int int high): high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] < A[mid A[mid + 1] 1] return unimodalmax(a, mid mid + 1, 1, high) high) else: else: return unimodalmax(a, low, low, mid mid + 1) 1) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + Θ(1)

procedure unimodalmax(list A, A, int int low, low, int int high): high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] < A[mid A[mid + 1] 1] return unimodalmax(a, mid mid + 1, 1, high) high) else: else: return unimodalmax(a, low, low, mid mid + 1) 1) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + Θ(1)

procedure unimodalmax(list A, A, int int low, low, int int high): high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] < A[mid A[mid + 1] 1] return unimodalmax(a, mid mid + 1, 1, high) high) else: else: return unimodalmax(a, low, low, mid mid + 1) 1) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + Θ(1) O(log n)

Unimodality II 1 3 4 5 7 8 10 12 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II A weakly unimodal array array is is one one that that can can be be split split into into a nondecreasing sequence followed by by a nonincreasing sequence. 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II A weakly unimodal array array is is one one that that can can be be split split into into a nondecreasing sequence followed by by a nonincreasing sequence. 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

Unimodality II 1 3 4 5 7 8 10 10 13 14 10 9 6 2

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high))

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high)) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + T( n T( n // 2 ) 2 ) + Θ(1)

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high)) T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + T( n T( n // 2 ) 2 ) + Θ(1)

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high)) T(1) T(1) c T(n) T(n) T( n T( n // 2 ) 2 ) + T( n T( n // 2 ) 2 ) + c

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high)) T(1) T(1) c T(n) T(n) T(n T(n // 2) 2) + T(n T(n // 2) 2) + c

procedure weakunimodalmax(list A, A, int int low, low, int int high): if if low low = high high - 1: 1: return A[low] let let mid mid = (high (high + low) low) / 2 if if A[mid] A[mid] < A[mid A[mid + 1] 1] return weakunimodalmax(a, mid mid + 1, 1, high) high) else else if if A[mid] A[mid] > A[mid A[mid + 1] 1] return weakunimodalmax(a, low, low, mid mid + 1) 1) else else return max(weakunimodalmax(a, low, low, mid mid + 1) 1) weakunimodalmax(a, mid mid + 1, 1, high)) T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2T ( n 2 ) +c 2 ( 2T ( n 4 ) +c ) +c 4 T ( n ) +2 c+c 4 = 4 T ( n 4 ) +3c 4( 2T ( n 8 ) +c ) +3c = 8 T ( n ) +4 c+3 c 8 = 8 T ( n 8 ) +7 c... 2 k T (n 2 k ) +(2k 1)c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2 c n c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2 c n c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2 c n c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2 c n c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2 c n c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c T(n) 2 k T (n 2 k ) +(2k 1)c 2 log 2 n T(1)+(2 log 2 n 1)c = nt(1)+c(n 1) c n+c(n 1) = 2c n c = O(n)

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c 4c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c 4c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c 4c c c c c c c

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c c c c c c c 4c cn

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c c c c c c c 4c cn (1 + 2 + 4 + + n / 2)c +cn

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c c c c c c c 4c cn (n 1)c +cn

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c c c c c c c 4c cn cn c + cn

T(1) T(1) c T(n) T(n) 2T(n // 2) 2) + c c c c c 2c c c c c c c c c c c 4c cn 2cn c

Another Recurrence Relation The recurrence relation T(1) T(1) = Θ(1) T(n) T(n) T( n T( n // 2 ) 2 ) + T( n T( n // 2 ) 2 ) + Θ(1) solves to T(n) = O(n) Intuitively, the recursion tree is bottomheavy: the bottom of the tree accounts for almost all of the work.

Unimodal Arrays Our recurrence shows that the work done is O(n), but this might not be a tight bound. Does our algorithm ever do Ω(n) work? Yes: What happens if all array values are equal to one another? Can we do better?

A Lower Bound Claim: Every correct algorithm for finding the maximum value in a unimodal array must do Ω(n) work in the worst-case. Note that this claim is over all possible algorithms, so the argument had better be watertight!

A Lower Bound We will prove that any algorithm for finding the maximum value of a unimodal array must, on at least one input, inspect all n locations. Proof idea: Suppose that the algorithm didn't do this.??????????????

A Lower Bound We will prove that any algorithm for finding the maximum value of a unimodal array must, on at least one input, inspect all n locations. Proof idea: Suppose that the algorithm didn't do this.??????????????

A Lower Bound We will prove that any algorithm for finding the maximum value of a unimodal array must, on at least one input, inspect all n locations. Proof idea: Suppose that the algorithm didn't do this. 0 0 0 0 0 0? 0 0 0 0 0 0 0

A Lower Bound We will prove that any algorithm for finding the maximum value of a unimodal array must, on at least one input, inspect all n locations. Proof idea: Suppose that the algorithm didn't do this. 0 0 0 0 0 0 10 0 0 0 0 0 0 0

A Lower Bound We will prove that any algorithm for finding the maximum value of a unimodal array must, on at least one input, inspect all n locations. Proof idea: Suppose that the algorithm didn't do this. 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Algorithmic Lower Bounds The argument we just saw is called an adversarial argument and is often used to establish algorithmic lower bounds. Idea: Show that if an algorithm doesn't do enough work, then it cannot distinguish two different inputs that require different outputs. Therefore, the algorithm cannot always be correct.

o Notation Let f, g : N N. We say that f(n) = o(g(n)) (f is little-o of g) iff lim n f (n) g(n) =0 In other words, f grows strictly slower than g. Often used to describe impossibility results. For example: There is no o(n)-time algorithm for finding the maximum element of a weakly unimodal array.

What Does This Mean? In the worst-case, our algorithm must do Ω(n) work. That's the same as a linear scan over the input array! Is our algorithm even worth it? Yes: In most cases, the runtime is Θ(log n) or close to it.

Binary Heaps

Data Structures Matter We have seen two instances where a better choice of data structure improved the runtime of an algorithm: Using adjacency lists instead of adjacency matrices in graph algorithms. Using a double-ended queue in 0/1 Dijkstra's algorithm. Today, we'll explore a data structure that is useful for improving algorithmic efficiency. We'll come back to this structure in a few weeks when talking about Prim's algorithm and Kruskal's algorithm.

Priority Queues A priority queue is a data structure for storing elements associated with priorities (often called keys). Optimized to find the element that currently has the smallest key. Supports the following operations: enqueue(k, v) which adds element v to the queue with key k. is-empty, which returns whether the queue is empty. dequeue-min, which removes the element with the least priority from the queue. Many implementations are possible with varying tradeoffs.

A Naive Implementation One simple way to implement a priority queue is with an unsorted array key/value pairs. To enqueue v with key k, append (k, v) to the array in time O(1). To check whether the priority queue is empty, check whether the underlying array is empty in time O(1). To dequeue-min, scan across the array to find an element with minimum key, then remove it in time O(n). Doing n enqueues and n dequeues takes time O(n2 ).

A Better Implementation 1 3 8 4 5 9

A Better Implementation 1 3 8 This tree obeys the heap heap property: each each node's node's key key is is less less than than or or equal equal to to all all its its descendants' keys. keys. 4 5 9 This tree obeys the

A Better Implementation 1 3 8 This tree obeys the heap heap property: each each node's node's key key is is less less than than or or equal equal to to all all its its descendants' keys. keys. 4 5 9 This tree obeys the

A Better Implementation 1 3 8 4 5 9

A Better Implementation 1 3 8 This is a complete binary binary tree: tree: every every level level except except the the last last one one is is filled filled in in completely. 4 5 9 This is a complete

A Better Implementation 1 3 8 4 5 9

A Better Implementation 1 3 8 4 5 9 2

A Better Implementation 1 3 8 4 5 9 2

A Better Implementation 1 3 2 4 5 9 8

A Better Implementation 1 3 2 4 5 9 8

A Better Implementation 1 3 2 4 5 9 8 0

A Better Implementation 1 3 2 4 5 9 8 0

A Better Implementation 1 3 2 0 5 9 8 4

A Better Implementation 1 0 2 3 5 9 8 4

A Better Implementation 0 1 2 3 5 9 8 4

A Better Implementation 0 1 2 3 5 9 8 4

A Better Implementation 0 1 2 3 5 9 8 4 2

A Better Implementation 0 1 2 3 5 9 8 4 2

A Better Implementation 0 1 2 2 5 9 8 4 3

A Better Implementation 0 1 2 2 5 9 8 4 3

A Better Implementation 0 1 2 2 5 9 8 4 3

A Better Implementation 1 2 2 5 9 8 4 3

A Better Implementation Yo. 'Sup. 1 2 2 5 9 8 4 3

A Better Implementation 1 2 2 5 9 8 4 3

A Better Implementation 1 2 2 5 9 8 4 3

A Better Implementation 1 2 2 5 9 8 4 3

A Better Implementation 3 1 2 2 5 9 8 4

A Better Implementation 1 3 2 2 5 9 8 4

A Better Implementation 1 2 2 3 5 9 8 4

A Better Implementation 1 2 2 3 5 9 8 4

Binary Heap Efficiency The enqueue and dequeue operations on a binary heap all run O(h), where h is the height of the tree. In a perfect binary tree of height h, there are 1 + 2 + 4 + 8 + + 2 h = 2 h+1 1 nodes. If there are n nodes, the maximum height would be found by setting n = 2 h+1 1. Solving, we get that h = log₂ (n + 1) 1 Thus h = Θ(log n), so enqueue and dequeue take time O(log n).

Implementing Binary Heaps It is extremely rare to actually implement a binary heap as a tree structure. Can encode the heap as an array: 1 3 8 4 5 9

Implementing Binary Heaps It is extremely rare to actually implement a binary heap as a tree structure. Can encode the heap as an array: 1 3 8 4 5 9

Implementing Binary Heaps It is extremely rare to actually implement a binary heap as a tree structure. Can encode the heap as an array: 1 3 8 4 5 9 1 3 8 4 5 9

Implementing Binary Heaps It is extremely rare to actually implement a binary heap as a tree structure. Can encode the heap as an array: 1 3 8 Assuming Assuming one-indexing: Node Node n has has children children at at positions positions 2n 2n and and 2n 2n + 1. 1. Node Node n has has its its parent parent at at position position n n // 2 2 4 5 9 1 3 8 4 5 9

Application: Heapsort

Sorting with Binary Heaps 3 1 4 0 5 9 2

Sorting with Binary Heaps 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 31 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 31 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 31 3 3 This This is is a max-heap (where (where larger larger values values are are on on top), top), as as opposed opposed to to a min-heap (where (where smaller smaller values values are are on on top). top). We'll We'll see see why why in in a minute. minute. 1 4 0 5 9 2

Sorting with Binary Heaps 31 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 3 31 4 3 1 4 0 5 9 2

Sorting with Binary Heaps 34 31 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 34 31 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 4 31 3 0 3 1 4 0 5 9 2

Sorting with Binary Heaps 4 31 3 0 3 1 4 0 5 9 2

Sorting with Binary Heaps 4 31 3 0 5 3 1 4 0 5 9 2

Sorting with Binary Heaps 4 35 3 0 1 3 1 4 0 5 9 2

Sorting with Binary Heaps 5 34 3 0 1 3 1 4 0 5 9 2

Sorting with Binary Heaps 5 34 3 0 1 3 1 4 0 5 9 2

Sorting with Binary Heaps 5 34 3 0 1 9 3 1 4 0 5 9 2

Sorting with Binary Heaps 5 34 9 0 1 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 9 34 5 0 1 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 9 34 5 0 1 3 3 1 4 0 5 9 2

Sorting with Binary Heaps 9 34 5 0 1 3 2 3 1 4 0 5 9 2

Sorting with Binary Heaps 9 34 5 0 1 3 2 3 1 4 0 5 9 2

Sorting with Binary Heaps 34 5 0 1 3 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 34 5 Oh no! 0 1 3 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 34 5 0 1 3 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 34 5 0 1 3 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 2 34 5 0 1 3 3 1 4 0 5 9 9

Sorting with Binary Heaps 2 34 5 0 1 3 3 1 4 0 5 9 9

Sorting with Binary Heaps 5 34 2 0 1 3 3 1 4 0 5 9 9

Sorting with Binary Heaps 5 34 3 0 1 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 5 34 3 0 1 2 3 1 4 0 5 9 9

Sorting with Binary Heaps 34 3 0 1 2 3 1 4 0 5 5 9

Sorting with Binary Heaps 2 34 3 0 1 3 1 4 0 5 5 9

Sorting with Binary Heaps 4 32 3 0 1 3 1 4 0 5 5 9

Sorting with Binary Heaps 4 32 3 0 1 3 1 4 0 5 5 9

Sorting with Binary Heaps 32 3 0 1 3 1 4 0 4 5 9

Sorting with Binary Heaps 1 32 3 0 3 1 4 0 4 5 9

Sorting with Binary Heaps 3 32 1 0 3 1 4 0 4 5 9

Sorting with Binary Heaps 3 32 1 0 3 1 4 0 4 5 9

Sorting with Binary Heaps 32 1 0 3 1 4 3 4 5 9

Sorting with Binary Heaps 0 32 1 3 1 4 3 4 5 9

Sorting with Binary Heaps 2 30 1 3 1 4 3 4 5 9

Sorting with Binary Heaps 2 30 1 3 1 4 3 4 5 9

Sorting with Binary Heaps 30 1 3 1 2 3 4 5 9

Sorting with Binary Heaps 30 1 3 1 2 3 4 5 9

Sorting with Binary Heaps 30 1 3 1 2 3 4 5 9

Sorting with Binary Heaps 30 3 1 2 3 4 5 9

Sorting with Binary Heaps 0 3 1 2 3 4 5 9

Sorting with Binary Heaps 0 3 1 2 3 4 5 9

Sorting with Binary Heaps 0 1 2 3 4 5 9

A Better Idea 3 1 4 0 5 9 2

A Better Idea 3 3 1 4 0 5 9 2

A Better Idea 3 3 1 4 0 5 9 2

A Better Idea 31 3 3 1 4 0 5 9 2

A Better Idea 31 3 3 1 4 0 5 9 2

A Better Idea 3 31 4 3 1 4 0 5 9 2

A Better Idea 34 31 3 4 1 3 0 5 9 2

A Better Idea 34 31 3 4 1 3 0 5 9 2

A Better Idea 4 31 3 0 4 1 3 0 5 9 2

A Better Idea 4 31 3 0 4 1 3 0 5 9 2

A Better Idea 4 31 3 0 5 4 1 3 0 5 9 2

A Better Idea 4 35 3 0 1 4 5 3 0 1 9 2

A Better Idea 5 34 3 0 1 5 4 3 0 1 9 2

A Better Idea 5 34 3 0 1 5 4 3 0 1 9 2

A Better Idea 5 34 3 0 1 9 5 4 3 0 1 9 2

A Better Idea 5 34 9 0 1 3 5 4 9 0 1 3 2

A Better Idea 9 34 5 0 1 3 9 4 5 0 1 3 2

A Better Idea 9 34 5 0 1 3 9 4 5 0 1 3 2

A Better Idea 9 34 5 0 1 3 2 9 4 5 0 1 3 2

A Better Idea 9 34 5 0 1 3 2 9 4 5 0 1 3 2

A Better Idea 34 5 0 1 3 2 9 4 5 0 1 3 2

A Better Idea 2 34 5 0 1 3 2 4 5 0 1 3 9

A Better Idea 5 34 2 0 1 3 5 4 2 0 1 3 9

A Better Idea 5 34 3 0 1 2 5 4 3 0 1 2 9

A Better Idea 5 34 3 0 1 2 5 4 3 0 1 2 9

A Better Idea 34 3 0 1 2 5 4 3 0 1 2 9

A Better Idea 2 34 3 0 1 2 4 3 0 1 5 9

A Better Idea 4 32 3 0 1 4 2 3 0 1 5 9

A Better Idea 4 32 3 0 1 4 2 3 0 1 5 9

A Better Idea 32 3 0 1 4 2 3 0 1 5 9

A Better Idea 1 32 3 0 1 2 3 0 4 5 9

A Better Idea 3 32 1 0 3 2 1 0 4 5 9

A Better Idea 3 32 1 0 3 2 1 0 4 5 9

A Better Idea 32 1 0 3 2 1 0 4 5 9

A Better Idea 0 32 1 0 2 1 3 4 5 9

A Better Idea 2 30 1 2 0 1 3 4 5 9

A Better Idea 2 30 1 2 0 1 3 4 5 9

A Better Idea 30 1 2 0 1 3 4 5 9

A Better Idea 30 1 1 0 2 3 4 5 9

A Better Idea 30 1 1 0 2 3 4 5 9

A Better Idea 30 1 0 2 3 4 5 9

A Better Idea 0 0 1 2 3 4 5 9

A Better Idea 0 0 1 2 3 4 5 9

A Better Idea 0 1 2 3 4 5 9

Heapsort The heapsort algorithm is as follows: Build a max-heap from the array elements, using the array itself to represent the heap. Repeatedly dequeue from the heap until all elements are placed in sorted order. This algorithm runs in time O(n log n), since it does n enqueues and n dequeues. Only requires O(1) auxiliary storage space, compared with O(n) space required in mergesort.

An Optimization: Heapify

Making a Binary Heap Suppose that you have n elements and want to build a binary heap from them. One way to do this is to enqueue all of them, one after another, into the binary heap. We can upper-bound the runtime as n calls to an O(log n) operation, giving a total runtime of O(n log n). Is that a tight bound?

Making a Binary Heap

Making a Binary Heap

Making a Binary Heap log₂ (n/2 + 1)

Making a Binary Heap log₂ (n/2 + 1) Total Runtime: Θ(n log n)

Quickly Making a Binary Heap Here is a slightly different algorithm for building a binary heap out of a set of data: Put the nodes, in any order, into a complete binary tree of the right size. (Shape property holds, but heap property might not.) For each node, starting at the bottom layer and going upward, run a bubble-down step on that node.

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 8 4 12 9 2 6 3 5

Quickly Making a Binary Heap 7 10 11 1 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 10 11 1 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 10 11 1 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 10 11 1 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 10 11 1 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 1 11 10 3 4 12 9 2 6 8 5

Quickly Making a Binary Heap 7 1 11 10 2 3 4 12 9 10 2 6 8 5

Quickly Making a Binary Heap 7 1 11 10 2 3 4 12 9 10 6 8 5

Quickly Making a Binary Heap 7 1 11 102 3 4 12 9 10 6 8 5

Quickly Making a Binary Heap 7 1 11 4 102 3 11 4 12 9 10 6 8 5

Quickly Making a Binary Heap 7 1 11 4 102 3 11 5 12 9 10 6 8 11 5

Quickly Making a Binary Heap 7 1 4 102 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 7 1 4 102 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 71 17 4 102 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 71 72 4 27 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Quickly Making a Binary Heap 1 72 4 7 3 11 5 12 9 10 6 8 11

Analyzing the Runtime At most half of the elements start one layer above that and can move down at most once. At most a quarter of the elements start one layer above that and can move down at most twice. At most an eighth of the elements start two layers above that and can move down at most thrice. More generally: At most n / 2 k of the elements can move down k steps. Can upper-bound the runtime with the sum T(n) log 2 n ni i=0 log 2 n 2 i =n i=0 i 2 i

Simplifying the Summation We want to simplify the sum log 2 n i=0 i 2 i Let's introduce a new variable x, then evaluate the sum when x = ½: log 2 n i=0 i x i If x < 1, each term is less than the previous, so log 2 n i=0 i x i < i=0 i x i

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = x (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = x (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = x (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = x (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = x (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = 1 (1 x) 2 x 2 (1 x) 2

Solving the Summation i=0 i x i = x i=0 = x i=0 i x i 1 d dx xi = x d dx ( i=0 x i ) = x d ( 1 ) dx 1 x = x = 1 (1 x) 2 x (1 x) 2

The Finishing Touches We know know that log 2 n T (n) n i=0 i x i < n i=0 i x i = Evaluating at x = ½, we get n x (1 x) 2 T (n) n(1/2) n(1/2) (1 (1/2)) 2= (1/2) =2n 2 So at most 2n swaps are performed! We visit each node once and do at most O(n) swaps, so the runtime is Θ(n).