CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion

Similar documents
CSCI-1200 Data Structures Fall 2017 Lecture 7 Order Notation & Basic Recursion

Data Structures Lecture 3 Order Notation and Recursion

CSCI-1200 Data Structures Spring 2016 Lecture 7 Iterators, STL Lists & Order Notation

CSCI-1200 Data Structures Fall 2011 Lecture 1 Introduction and Background

CSCI-1200 Data Structures Fall 2017 Lecture 12 Advanced Recursion

Computer Science II Lecture 2 Strings, Vectors and Recursion

CSCI-1200 Computer Science II Fall 2007 Lecture 1 Introduction and Background

CSCI-1200 Data Structures Fall 2014 Lecture 12 Recursion

CSCI-1200 Data Structures Spring 2017 Lecture 13 Advanced Recursion

Today s Outline. CSE 326: Data Structures Asymptotic Analysis. Analyzing Algorithms. Analyzing Algorithms: Why Bother? Hannah Takes a Break

CSE 143. Complexity Analysis. Program Efficiency. Constant Time Statements. Big Oh notation. Analyzing Loops. Constant Time Statements (2) CSE 143 1

CSE 146. Asymptotic Analysis Interview Question of the Day Homework 1 & Project 1 Work Session

CS/ENGRD 2110 Object-Oriented Programming and Data Structures Spring 2012 Thorsten Joachims. Lecture 10: Asymptotic Complexity and

10/5/2016. Comparing Algorithms. Analyzing Code ( worst case ) Example. Analyzing Code. Binary Search. Linear Search

CSE373: Data Structures and Algorithms Lecture 4: Asymptotic Analysis. Aaron Bauer Winter 2014

CSCI-1200 Computer Science II Spring 2006 Lecture 10 Recursion Examples

Computer Science II CSci 1200 Test 1 Overview and Practice

Algorithm Analysis. Spring Semester 2007 Programming and Data Structure 1

Unit #3: Recursion, Induction, and Loop Invariants

Recursion. Example R1

Outline. runtime of programs algorithm efficiency Big-O notation List interface Array lists

8/5/10 TODAY'S OUTLINE. Recursion COMP 10 EXPLORING COMPUTER SCIENCE. Revisit search and sorting using recursion. Recursion WHAT DOES THIS CODE DO?

CSCI-1200 Data Structures Fall 2017 Lecture 13 Problem Solving Techniques

CSCI-1200 Data Structures Fall 2017 Lecture 10 Vector Iterators & Linked Lists

CSCI-1200 Data Structures Spring 2018 Lecture 10 Vector Iterators & Linked Lists

Analysis of Algorithms. CS 1037a Topic 13

CSCI-1200 Data Structures Spring 2018 Lecture 14 Associative Containers (Maps), Part 1 (and Problem Solving Too)

CSCI 102L - Data Structures Midterm Exam #2 Spring 2011

Introduction to the Analysis of Algorithms. Algorithm

Measuring algorithm efficiency

Agenda. The worst algorithm in the history of humanity. Asymptotic notations: Big-O, Big-Omega, Theta. An iterative solution

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Priority Queues / Heaps Date: 9/27/17

PROGRAM EFFICIENCY & COMPLEXITY ANALYSIS

Data Structures CSci 1200 Test 1 Questions

CS103L SPRING 2017 UNIT 8: RECURSION

Unit #2: Recursion, Induction, and Loop Invariants

Recursion & Performance. Recursion. Recursion. Recursion. Where Recursion Shines. Breaking a Problem Down

CSE 332 Spring 2013: Midterm Exam (closed book, closed notes, no calculators)

1 Dynamic Memory continued: Memory Leaks

Computer Science 210 Data Structures Siena College Fall Topic Notes: Complexity and Asymptotic Analysis

l Determine if a number is odd or even l Determine if a number/character is in a range - 1 to 10 (inclusive) - between a and z (inclusive)

Recursion Chapter 8. What is recursion? How can a function call itself? How can a function call itself?

Discussion 2C Notes (Week 5, February 4) TA: Brian Choi Section Webpage:

CSCI-1200 Data Structures Fall 2013 Lecture 9 Iterators & Lists

Algorithm Complexity Analysis: Big-O Notation (Chapter 10.4) Dr. Yingwu Zhu

EECS 477: Introduction to algorithms. Lecture 6

Lecture 15 Binary Search Trees

CMPSCI 187: Programming With Data Structures. Lecture 5: Analysis of Algorithms Overview 16 September 2011

Lecture 15 Notes Binary Search Trees

Chapter 12 Supplement: Recursion with Java 1.5. Mr. Dave Clausen La Cañada High School

CMSC 341 Lecture 16/17 Hashing, Parts 1 & 2

Recursion. Recursion is: Recursion splits a problem:

Recursion Chapter 3.5

SEARCHING AND SORTING HINT AT ASYMPTOTIC COMPLEXITY

Recursion CSCI 136: Fundamentals of Computer Science II Keith Vertanen Copyright 2011

! Determine if a number is odd or even. ! Determine if a number/character is in a range. - 1 to 10 (inclusive) - between a and z (inclusive)

CSE 373 APRIL 3 RD ALGORITHM ANALYSIS

Lecture Notes on Binary Search Trees

Lecture Notes on Memory Layout

ECE 122. Engineering Problem Solving Using Java

CPSC 211, Sections : Data Structures and Implementations, Honors Final Exam May 4, 2001

Algorithm Analysis. CENG 707 Data Structures and Algorithms

The Limits of Sorting Divide-and-Conquer Comparison Sorts II

1 Deletion in singly linked lists (cont d) 1 Other Functions. 1 Doubly Linked Lists. 1 Circular lists. 1 Linked lists vs. arrays

CS 310: Order Notation (aka Big-O and friends)

ASYMPTOTIC COMPLEXITY

Run Times. Efficiency Issues. Run Times cont d. More on O( ) notation

Recitation 9. Prelim Review

Complexity of Algorithms

Final Exam Solutions PIC 10B, Spring 2016

Recursion. Fundamentals of Computer Science

CSE 373 MAY 24 TH ANALYSIS AND NON- COMPARISON SORTING

CS1 Lecture 22 Mar. 6, 2019

Recursion. COMS W1007 Introduction to Computer Science. Christopher Conway 26 June 2003

Recursion Chapter 8. What is recursion? How can a function call itself? How can a function call itself? contains a reference to itself.

Lecture Notes on Binary Search Trees

FORM 2 (Please put your name and form # on the scantron!!!!)

! Determine if a number is odd or even. ! Determine if a number/character is in a range. ! Assign a category based on ranges (wind speed)

Introduction to Programming I

CSCI-1200 Data Structures Fall 2018 Lecture 22 Hash Tables, part 2 & Priority Queues, part 1

Chapter 13. Recursion. Copyright 2016 Pearson, Inc. All rights reserved.

Topics Applications Most Common Methods Serial Search Binary Search Search by Hashing (next lecture) Run-Time Analysis Average-time analysis Time anal

Jalil Boudjadar, Tommy Färnqvist. IDA, Linköping University

LECTURE 17. Array Searching and Sorting

CSCI-1200 Data Structures Spring 2018 Lecture 8 Templated Classes & Vector Implementation

CSCI-1200 Data Structures Fall 2017 Lecture 9 Iterators & STL Lists

CSCA48 Winter 2018 Week 10:Algorithm Analysis. Marzieh Ahmadzadeh, Nick Cheng University of Toronto Scarborough

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

Identify recursive algorithms Write simple recursive algorithms Understand recursive function calling

CSE 373: Data Structures and Algorithms

Section 05: Midterm Review

Data Structures CSci 1200 Test 2 Questions

G Programming Languages - Fall 2012

6. Pointers, Structs, and Arrays. 1. Juli 2011

CSCI 261 Computer Science II


Algorithm Analysis CISC4080 CIS, Fordham Univ. Instructor: X. Zhang

CSCI-1200 Computer Science II Spring 2006 Test 3 Practice Problem Solutions

Discussion 2C Notes (Week 5, February 4) TA: Brian Choi Section Webpage:

You should know the first sum above. The rest will be given if you ever need them. However, you should remember that,, and.

Transcription:

CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion Review from Lectures 5 & 6 Arrays and pointers, Pointer arithmetic and dereferencing, Types of memory ( automatic, static, dynamic) Dynamic allocation of arrays, Drawing pictures to explain stack vs. heap memory allocation, Memory debugging Today s Lecture Algorithm Analysis, Formal Definition of Order Notation Simple recursion, Visualization of recursion, Iteration vs. Recursion Rules for writing recursive functions, Lots of examples! 7.1 Algorithm Analysis Why should we bother? We want to do better than just implementing and testing every idea we have. We want to know why one algorithm is better than another. We want to know the best we can do. (This is often quite hard.) How do we do it? There are several options, including: Don t do any analysis; just use the first algorithm you can think of that works. Implement and time algorithms to choose the best. Analyze algorithms by counting operations while assigning different weights to different types of operations based on how long each takes. Analyze algorithms by assuming each operation requires the same amount of time. Count the total number of operations, and then multiply this count by the average cost of an operation. 7.2 Exercise: Counting Example Suppose arr is an array of n doubles. Here is a simple fragment of code to sum of the values in the array: double sum = 0; sum += arr[i]; What is the total number of operations performed in executing this fragment? describing the number of operations in terms of n. Come up with a function 7.3 Exercise: Which Algorithm is Best? A venture capitalist is trying to decide which of 3 startup companies to invest in and has asked for your help. Here s the timing data for their prototype software on some different size test cases: n foo-a foo-b foo-c 10 10 u-sec 5 u-sec 1 u-sec 20 13 u-sec 10 u-sec 8 u-sec 30 15 u-sec 15 u-sec 27 u-sec 100 20 u-sec 50 u-sec 1000 u-sec 1000??? Which company has the best algorithm?

7.4 Order Notation Definition In this course we will focus on the intuition of order notation. This topic will be covered again, in more depth, in later computer science courses. Definition: Algorithm A is order f(n) denoted O(f(n)) if constants k and n 0 exist such that A requires no more than k f(n) time units (operations) to solve a problem of size n n 0. For example, algorithms requiring 3n + 2, 5n 3, and 14 + 17n operations are all O(n). This is because we can select values for k and n 0 such that the definition above holds. (What values?) Likewise, algorithms requiring n 2 /10 + 15n 3 and 10000 + 35n 2 are all O(n 2 ). Intuitively, we determine the order by finding the asymptotically dominant term (function of n) and throwing out the leading constant. This term could involve logarithmic or exponential functions of n. Implications for analysis: We don t need to quibble about small differences in the numbers of operations. We also do not need to worry about the different costs of different types of operations. We don t produce an actual time. We just obtain a rough count of the number of operations. This count is used for comparison purposes. In practice, this makes analysis relatively simple, quick and (sometimes unfortunately) rough. 7.5 Common Orders of Magnitude O(1), a.k.a. CONSTANT: The number of operations is independent of the size of the problem. e.g., compute quadratic root. O(log n), a.k.a. LOGARITHMIC. e.g., dictionary lookup, binary search. O(n), a.k.a. LINEAR. e.g., sum up a list. O(n log n), e.g., sorting. O(n 2 ), O(n 3 ), O(n k ), a.k.a. POLYNOMIAL. e.g., find closest pair of points. O(2 n ), O(k n ), a.k.a. EXPONENTIAL. e.g., Fibonacci, playing chess. 7.6 Exercise: A Slightly Harder Example Here s an algorithm to determine if the value stored in variable x is also in an array called foo. Can you analyze it? What did you do about the if statement? What did you assume about where the value stored in x occurs in the array (if at all)? int loc=0; bool found = false; while (!found && loc < n) { if (x == foo[loc]) found = true; else loc++; if (found) cout << "It is there!\n"; 7.7 Best-Case, Average-Case and Worst-Case Analysis For a given fixed size array, we might want to know: The fewest number of operations (best case) that might occur. The average number of operations (average case) that will occur. The maximum number of operations (worst case) that can occur. The last is the most common. The first is rarely used. On the previous algorithm, the best case is O(1), but the average case and worst case are both O(n). 2

7.8 Approaching An Analysis Problem Decide the important variable (or variables) that determine the size of the problem. For arrays and other container classes this will generally be the number of values stored. Decide what to count. The order notation helps us here. If each loop iteration does a fixed (or bounded) amount of work, then we only need to count the number of loop iterations. We might also count specific operations. For example, in the previous exercise, we could count the number of comparisons. Do the count and use order notation to describe the result. 7.9 Exercise: Order Notation For each version below, give an order notation estimate of the number of operations as a function of n: 1. int count=0; for (int j=0; j<n; ++j) 2. int count=0; for (int j=0; j<n; ++j) 3. int count=0; for (int j=i; j<n; ++j) 7.10 Recursive Definitions of Factorials and Integer Exponentiation Factorial is defined for non-negative integers as: { n (n 1)! n > 0 n! = 1 n == 0 These are both examples of recursive definitions. 7.11 Recursive C++ Functions Computing integer powers is defined as: { n p n n p 1 p > 0 = 1 p == 0 C++, like other modern programming languages, allows functions to call themselves. This gives a direct method of implementing recursive functions. Here are the recursive implementations of factorial and integer power: int fact(int n) { if (n == 0) { return 1; else { int result = fact(n-1); return n * result; int intpow(int n, int p) { if (p == 0) { return 1; else { return n * intpow( n, p-1 ); 3

7.12 The Mechanism of Recursive Function Calls For each recursive call (or any function call), a program creates an activation record to keep track of: Completely separate instances of the parameters and local variables for the newly-called function. The location in the calling function code to return to when the newly-called function is complete. (Who asked for this function to be called? Who wants the answer?) Which activation record to return to when the function is done. For recursive functions this can be confusing since there are multiple activation records waiting for an answer from the same function. This is illustrated in the following diagram of the call fact(4). Each box is an activation record, the solid lines indicate the function calls, and the dashed lines indicate the returns. Inside of each box we list the parameters and local variables and make notes about the computation. tmp = fact(4) fact(4) n=4 result = fact(3) return 4*6 fact(3) n=3 result = fact(2) return 3*2 fact(2) n=2 result = fact(1) return 2*1 fact(1) n=1 result = fact(0) return 1*1 24 6 2 1 1 fact(0) n=0 return 1 This chain of activation records is stored in a special part of program memory called the stack. 7.13 Iteration vs. Recursion Each of the above functions could also have been written using a for or while loop, i.e. iteratively. For example, here is an iterative version of factorial: int ifact(int n) { int result = 1; for (int i=1; i<=n; ++i) result = result * i; return result; Often writing recursive functions is more natural than writing iterative functions, especially for a first draft of a problem implementation. You should learn how to recognize whether an implementation is recursive or iterative, and practice rewriting one version as the other. Note: We ll see that not all recursive functions can be easily rewritten in iterative form! Note: The order notation for the number of operations for the recursive and iterative versions of an algorithm is usually the same. However in C, C++, Java, and some other languages, iterative functions are generally faster than their corresponding recursive functions. This is due to the overhead of the function call mechanism. Compiler optimizations will sometimes (but not always!) reduce the performance hit by automatically eliminating the recursive function calls. This is called tail call optimization. 7.14 Exercises 1. Draw a picture to illustrate the activation records for the function call cout << intpow(4, 4) << endl; 2. Write an iterative version of intpow. 3. What is the order notation for the two versions of intpow? 4

7.15 Rules for Writing Recursive Functions Here is an outline of five steps that are useful in writing and debugging recursive functions. Note: You don t have to do them in exactly this order... 1. Handle the base case(s). 2. Define the problem solution in terms of smaller instances of the problem. Use wishful thinking, i.e., if someone else solves the problem of fact(4) I can extend that solution to solve fact(5). This defines the necessary recursive calls. It is also the hardest part! 3. Figure out what work needs to be done before making the recursive call(s). 4. Figure out what work needs to be done after the recursive call(s) complete(s) to finish the computation. (What are you going to do with the result of the recursive call?) 5. Assume the recursive calls work correctly, but make sure they are progressing toward the base case(s)! 7.16 Location of the Recursive Call Example: Printing the Contents of a Vector Here is a function to print the contents of a vector. Actually, it s two functions: a driver function, and a true recursive function. It is common to have a driver function that just initializes the first recursive function call. void print_vec(std::vector<int>& v, unsigned int i) { if (i < v.size()) { cout << i << ": " << v[i] << endl; print_vec(v, i+1); void print_vec(std::vector<int>& v) { print_vec(v, 0); What will this print when called in the following code? int main() { std::vector<int> a; a.push_back(3); a.push_back(5); a.push_back(11); a.push_back(17); print_vec(a); How can you change the second print vec function as little as possible so that this code prints the contents of the vector in reverse order? 5

7.17 Fibonacci Optimization: Order Notation of Time vs. Space The Fibonacci sequence is defined: 1 n == 0 Fib n = 1 n == 1 Fib n 1 + Fib n 2 n > 1 1. Write a simple recursive version of Fibonacci that is a direct translation of the mathematical definition of the Fibonacci sequence. 2. Write an iterative version of Fibonacci that uses a vector to improve the running time of the function. 3. What is the order notation of the running time for each version? 4. What is the order notation of the memory usage for each version? 7.18 Binary Search Suppose you have a std::vector<t> v (for a placeholder type T ), sorted so that: v[0] <= v[1] <= v[2] <=... Now suppose that you want to find if a particular value x is in the vector somewhere. How can you do this without looking at every value in the vector? The solution is a recursive algorithm called binary search, based on the idea of checking the middle item of the search interval within the vector and then looking either in the lower half or the upper half of the vector, depending on the result of the comparison. template <class T> bool binsearch(const std::vector<t> &v, int low, int high, const T &x) { if (high == low) return x == v[low]; int mid = (low+high) / 2; if (x <= v[mid]) return binsearch(v, low, mid, x); else return binsearch(v, mid+1, high, x); template <class T> bool binsearch(const std::vector<t> &v, const T &x) { return binsearch(v, 0, v.size()-1, x); 7.19 Exercises 1. Write a non-recursive version of binary search. 2. If we replaced the if-else structure inside the recursive binsearch function (above) with if ( x < v[mid] ) return binsearch( v, low, mid-1, x ); else return binsearch( v, mid, high, x ); would the function still work correctly? 6