Chapter 5: Recursion as a Problem-Solving Technique BACKTRACKING RECURSIVE GRAMMARS MATRIX OPERATIONS MATHEMATICAL INDUCTION RECURRENCE RELATIONS CS 240.

Slides:



Advertisements
Similar presentations
Recursion.
Advertisements

CS 240Chapter 7 - QueuesPage 29 Chapter 7 Queues The queue abstract data type is essentially a list using the FIFO (first-in-first-out) policy for adding.
Chapter 7: Queues QUEUE IMPLEMENTATIONS QUEUE APPLICATIONS CS
Divide-and-Conquer Recursive in structure –Divide the problem into several smaller sub-problems that are similar to the original but smaller in size –Conquer.
True or false A variable of type char can hold the value 301. ( F )
Computer Science 1620 Loops.
CS5371 Theory of Computation
Iteration This week we will learn how to use iteration in C++ Iteration is the repetition of a statement or block of statements in a program. C++ has three.
Chapter 6 Control Structures.
Liang, Introduction to Programming with C++, Second Edition, (c) 2010 Pearson Education, Inc. All rights reserved Chapter 8 Multidimensional.
DAST 2005 Tirgul 6 Heaps Induction. DAST 2005 Heaps A binary heap is a nearly complete binary tree stored in an array object In a max heap, the value.
analysis, plug ‘n’ chug, & induction
Induction and recursion
Ch. 8 & 9 – Linear Sorting and Order Statistics What do you trade for speed?
Induction and recursion
Analysis of Algorithm Lecture 3 Recurrence, control structure and few examples (Part 1) Huma Ayub (Assistant Professor) Department of Software Engineering.
CS161 Topic #15 1 Today in CS161 Lecture #15 Practicing! Writing Programs to Practice Write a game program (1 player) of Mad Math Reuse the functions to.
C. – C. Yao Data Structure. C. – C. Yao Chap 1 Basic Concepts.
Outlines Chapter 3 –Chapter 3 – Loops & Revision –Loops while do … while – revision 1.
Copyright © 2012 Pearson Education, Inc. Chapter 8 Two Dimensional Arrays.
True or False: Boolean Expression Boolean expression are expressions which evaluate to "true" or "false“ Primary operators to combine expressions: && (and),
CSE 20 Lecture 12 Induction CK Cheng 1. Induction Outlines Introduction Theorem Examples: The complexity calculation – Tower of Hanoi – Merge Sort – Fibonacci.
Chapter 1: Introduction Mathematical Proofs Mathematical Induction CS 340 Page 1.
Chapter 1 Introduction. Goals Why the choice of algorithms is so critical when dealing with large inputs Basic mathematical background Review of Recursion.
Chapter 3 (Part 3): Mathematical Reasoning, Induction & Recursion  Recursive Algorithms (3.5)  Program Correctness (3.6)
Programming Principles II Lecture Notes 5 Recursion Andreas Savva.
1 7.Algorithm Efficiency What to measure? Space utilization: amount of memory required  Time efficiency: amount of time required to process the data Depends.
Arrays Module 6. Objectives Nature and purpose of an array Using arrays in Java programs Methods with array parameter Methods that return an array Array.
Hello.java Program Output 1 public class Hello { 2 public static void main( String [] args ) 3 { 4 System.out.println( “Hello!" ); 5 } // end method main.
Mathematical Induction I Lecture 4: Sep 16. This Lecture Last time we have discussed different proof techniques. This time we will focus on probably the.
© Copyright 2013 by Pearson Education, Inc. All Rights Reserved. 1 Chapter 8 Multidimensional Arrays.
Exposure C++ Chapter XXI C++ Data Structures, the 2D Array apmatrix Implementation.
COMPUTER PROGRAMMING. Iteration structures (loops) There may be a situation when you need to execute a block of code several number of times. In general,
Basic Mathematics Chapter 1 (1.2 and 1.3) Weiss. Recursion / Slide 2 Logarithms * Definition: if and only if * Theorem 1.1: n Proof: apply the definition.
Savitch - Chapters 9&11 CS Pointers A pointer holds the memory address of a variable. Main Memory Byte # Byte # Byte # Byte.
Chapter 7 Selection Dept of Computer Engineering Khon Kaen University.
 2000 Deitel & Associates, Inc. All rights reserved. Chapter 12 - Templates Outline 12.1Introduction 12.2Function Templates 12.3Overloading Template Functions.
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Stacks.
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Stacks.
Section 5 - Arrays. Problem solving often requires information be viewed as a “list” List may be one-dimensional or multidimensional List is implemented.
CS 240Chapter 5 - RecursionPage 37 Chapter 5 Recursion Recursion can be a very effective technique for solving what would otherwise be extremely elaborate.
EEE 145 Programming in C++ Arrays 0. Motivation You may need to define many variables of the same type. –Defining so many variables one by one is cumbersome.
CS 103 Discrete Structures Lecture 13 Induction and Recursion (1)
1 More Operator Overloading Chapter Objectives You will be able to: Define and use an overloaded operator to output objects of your own classes.
Divide-and-Conquer UNC Chapel HillZ. Guo. Divide-and-Conquer It’s a technique instead of an algorithm Recursive in structure – Divide the problem into.
1 INFO 2950 Prof. Carla Gomes Module Induction Rosen, Chapter 4.
1/32 This Lecture Substitution model An example using the substitution model Designing recursive procedures Designing iterative procedures Proving that.
 2008 Pearson Education, Inc. All rights reserved. 1 Arrays and Vectors.
1 Becoming More Effective with C++ … Day Two Stanley B. Lippman
Alternate Version of STARTING OUT WITH C++ 4 th Edition Chapter 5 Looping.
Arrays Chapter 7. MIS Object Oriented Systems Arrays UTD, SOM 2 Objectives Nature and purpose of an array Using arrays in Java programs Methods.
1 Chapter 1 C++ Templates Readings: Sections 1.6 and 1.7.
CS 240Chapter 10 – TreesPage Chapter 10 Trees The tree abstract data type provides a hierarchical to the representation of certain types of relationships.
Prof. Amr Goneid, AUC1 Analysis & Design of Algorithms (CSCE 321) Prof. Amr Goneid Department of Computer Science, AUC Part 3. Time Complexity Calculations.
CS Class 04 Topics  Selection statement – IF  Expressions  More practice writing simple C++ programs Announcements  Read pages for next.
Functions and Libraries. Reference parameters void setToZero(int var) { var = 0; } int main() { int var = 0; setToZero(var); cout
Chapter 15 Running Time Analysis. Topics Orders of Magnitude and Big-Oh Notation Running Time Analysis of Algorithms –Counting Statements –Evaluating.
1 7.Algorithm Efficiency These factors vary from one machine/compiler (platform) to another  Count the number of times instructions are executed So, measure.
Problem Session Working in pairs of two, solve the following problem...
Hubert Chan (Chapters 1.6, 1.7, 4.1)
Chapter 5 Recursion as a Problem-Solving Technique
Engineering Problem Solving with C++, Etter/Ingber
Hubert Chan (Chapters 1.6, 1.7, 4.1)
CS 213: Data Structures and Algorithms
Chapter 5 Induction and Recursion
Stack Data Structure, Reverse Polish Notation, Homework 7
Multidimensional Arrays
do/while Selection Structure
CS150 Introduction to Computer Science 1
Recursion as a Problem-Solving Technique
Presentation transcript:

Chapter 5: Recursion as a Problem-Solving Technique BACKTRACKING RECURSIVE GRAMMARS MATRIX OPERATIONS MATHEMATICAL INDUCTION RECURRENCE RELATIONS CS

CS Recursion can be a very effective technique for solving what would otherwise be extremely elaborate problems. Sample recursive applications include:  Backtracking algorithms.  Programming language definition.  Matrix operations. In addition, a solid understanding of recursion is helpful in analyzing the time complexity of algorithms.  Mathematical induction.  Recurrence relations. Recursion-related analysis techniques include:

CS Recursive Backtracking Example: Flood Fill Algorithm Starting with a “seed” pixel that’s inside a polygonal region, recursively visit the four adjacent pixels, coloring any that haven’t been colored, and that aren’t on the polygon’s boundary. Reaching the boundary is the recursion’s termination condition. Seed pixel Boundary pixel LRUD-visited pixel void floodfill(int x, int y) { if (!filled(x,y)) { color(x,y); floodfill(x-1,y); // Left floodfill(x+1,y); // Right floodfill(x,y-1); // Up floodfill(x,y+1); // Down }

CS Recursive Grammar Example: A Calculator Grammar Languages (e.g., programming languages) are often defined by their grammars, sets of recursive rules which provide syntax. program:END expr_list END expr_list:expression ; expression ; expr_list expression:term + expression term – expression term term:primary / term primary * term primary primary:NUMBER NAME NAME = expression - primary ( expression ) Using this grammar, the following is a syntactically correct calculator program: pi = ; rad = 2.5; ht = 10; area = pi * rad * rad; surfacearea = 2 * (area + pi * rad * ht); END Recursive grammars are also prominent in more sophisticated languages, making the following language features possible: nested loops, conditionals, function calls nested loops, conditionals, function calls cascaded operators ( >, =, etc.) cascaded operators ( >, =, etc.) multiple cases in a switch statement multiple cases in a switch statement

CS Many matrix operations may be defined recursively, with combinations of submatrix operations used to implement the large matrix operation.                                               Note that a matrix’s determinant is used to determine, among other things, whether the matrix is invertible. Recursive Matrix Operation Example: Determinants

CS //////////////////////////////////////////// // Class definition file: Matrix.h // // The matrix class has two data members: // // a square array of integer values (all // // between 0 and 9), and an integer indi- // // cating the array size. Its member // // functions include constructors, func- // // tions to set and access specific array // // elements, a function to access a sub- // // array, a recursive determinant func- // // tion, and an output operator. // //////////////////////////////////////////// #ifndef MATRIX_H #include using namespace std; typedef int elementType; const int MAX_GRID_SIZE = 7; class matrix { public: // Class constructors matrix() {size = 0;} matrix(const matrix &m); matrix(int sz); //////////////////////////////////////////// // Class definition file: Matrix.h // // The matrix class has two data members: // // a square array of integer values (all // // between 0 and 9), and an integer indi- // // cating the array size. Its member // // functions include constructors, func- // // tions to set and access specific array // // elements, a function to access a sub- // // array, a recursive determinant func- // // tion, and an output operator. // //////////////////////////////////////////// #ifndef MATRIX_H #include using namespace std; typedef int elementType; const int MAX_GRID_SIZE = 7; class matrix { public: // Class constructors matrix() {size = 0;} matrix(const matrix &m); matrix(int sz); // Member functions int getSize() const { return size; } void setElement(int i, int j, elementType item); elementType getElement(int i, int j) { return table[i][j]; } elementType determinant(); friend ostream& operator << (ostream &os, const matrix &m); protected: // Data members elementType table[MAX_GRID_SIZE] [MAX_GRID_SIZE]; int size; // Member function matrix minor(int i, int j); }; #define MATRIX_H #endif // Member functions int getSize() const { return size; } void setElement(int i, int j, elementType item); elementType getElement(int i, int j) { return table[i][j]; } elementType determinant(); friend ostream& operator << (ostream &os, const matrix &m); protected: // Data members elementType table[MAX_GRID_SIZE] [MAX_GRID_SIZE]; int size; // Member function matrix minor(int i, int j); }; #define MATRIX_H #endif Recursive Determinant Program Example

CS //////////////////////////////////////////// // Class implementation file: Matrix.cpp // // The implementation of the copy and // // initializing constructors, the setEle- // // ment, determinant, and minor member // // functions, and the output operator. // //////////////////////////////////////////// #include #include "Matrix.h" using namespace std; // Copy constructor: Copies existing mat.// matrix::matrix(const matrix &m) { size = m.size; for (int row = 0; row < m.size; row++) for (int col = 0; col < m.size; col++) table[row][col] = m.table[row][col]; } // Initializing constructor: Sets *this // // up as a sz x sz matrix of zeros. // matrix::matrix(int sz) { size = sz; for (int row = 0; row < sz; row++) for (int col = 0; col < sz; col++) table[row][col] = 0; } //////////////////////////////////////////// // Class implementation file: Matrix.cpp // // The implementation of the copy and // // initializing constructors, the setEle- // // ment, determinant, and minor member // // functions, and the output operator. // //////////////////////////////////////////// #include #include "Matrix.h" using namespace std; // Copy constructor: Copies existing mat.// matrix::matrix(const matrix &m) { size = m.size; for (int row = 0; row < m.size; row++) for (int col = 0; col < m.size; col++) table[row][col] = m.table[row][col]; } // Initializing constructor: Sets *this // // up as a sz x sz matrix of zeros. // matrix::matrix(int sz) { size = sz; for (int row = 0; row < sz; row++) for (int col = 0; col < sz; col++) table[row][col] = 0; } // SetElement Member Function: Sets the // // (i,j) element of the matrix to item. // void matrix::setElement(int i, int j, elementType e) { assert ((0<=i) && (i<size) && (0<=j) && (j<size)); table[i][j] = e; } // Determinant Member Function: Calculates // // & returns the determinant of the matrix. // elementType matrix::determinant() { elementType value = 0; if (size == 1) return table[0][0]; for (int col = 0; col < size; col++) { value += (elementType)pow(-1, 0+col) * table[0][col] * minor(0, col).determinant(); } return value; } // SetElement Member Function: Sets the // // (i,j) element of the matrix to item. // void matrix::setElement(int i, int j, elementType e) { assert ((0<=i) && (i<size) && (0<=j) && (j<size)); table[i][j] = e; } // Determinant Member Function: Calculates // // & returns the determinant of the matrix. // elementType matrix::determinant() { elementType value = 0; if (size == 1) return table[0][0]; for (int col = 0; col < size; col++) { value += (elementType)pow(-1, 0+col) * table[0][col] * minor(0, col).determinant(); } return value; } Notice how the size×size matrix is being evaluated recursively by using the top row to expand into size (size- 1)×(size-1) submatrices.

CS // Output Operator: Outputs matrix // // as a grid of size rows with // // size columns in each row. // ostream& operator << (ostream &os, const matrix &m) { for (int row = 0; row < m.getSize(); row++) { for (int col = 0; col < m.getSize(); col++) os << setw(4) << m.table[row][col]; os << endl; } return os; } // Output Operator: Outputs matrix // // as a grid of size rows with // // size columns in each row. // ostream& operator << (ostream &os, const matrix &m) { for (int row = 0; row < m.getSize(); row++) { for (int col = 0; col < m.getSize(); col++) os << setw(4) << m.table[row][col]; os << endl; } return os; } // Minor Member Function: If *this is // // an nXn matrix, then this returns // // the (n-1)X(n-1) matrix that is // // *this w/row i & column j removed. // matrix matrix::minor(int i, int j) { int subrow, subcol; assert (size > 1); matrix submat(size-1); subrow = 0; for (int row = 0; row < size; row++) { subcol = 0; if (row != i) { for (int col = 0; col < size; col++) if (col != j) { submat.setElement(subrow, subcol, table[row][col]); subcol++; } subrow++; } return submat; } // Minor Member Function: If *this is // // an nXn matrix, then this returns // // the (n-1)X(n-1) matrix that is // // *this w/row i & column j removed. // matrix matrix::minor(int i, int j) { int subrow, subcol; assert (size > 1); matrix submat(size-1); subrow = 0; for (int row = 0; row < size; row++) { subcol = 0; if (row != i) { for (int col = 0; col < size; col++) if (col != j) { submat.setElement(subrow, subcol, table[row][col]); subcol++; } subrow++; } return submat; }

CS //////////////////////////////////////////////////// // Program file: matrixDriver.cpp // // This program tests the matrix class by // // creating a random matrix of a user-specified // // size, outputting it, & taking its determinant. // //////////////////////////////////////////////////// #include #include "Matrix.h" using namespace std; int generateRandomNumber(int lowerBound, int upperBound); // The main function randomly generates & outputs // // a square matrix,, & determines its determinant.// void main() { int gridSize; cout << "SPECIFY THE MATRIX SIZE (a positive " << "integer less than " << MAX_GRID_SIZE+1 << "): "; cin >> gridSize; while ((gridSize MAX_GRID_SIZE)) { cout << "SORRY, ONLY VALUES BETWEEN 1 AND " \n "; cout << "SPECIFY THE MATRIX SIZE (a positive " << "integer less than " << MAX_GRID_SIZE+1 << "): "; cin >> gridSize; } //////////////////////////////////////////////////// // Program file: matrixDriver.cpp // // This program tests the matrix class by // // creating a random matrix of a user-specified // // size, outputting it, & taking its determinant. // //////////////////////////////////////////////////// #include #include "Matrix.h" using namespace std; int generateRandomNumber(int lowerBound, int upperBound); // The main function randomly generates & outputs // // a square matrix,, & determines its determinant.// void main() { int gridSize; cout << "SPECIFY THE MATRIX SIZE (a positive " << "integer less than " << MAX_GRID_SIZE+1 << "): "; cin >> gridSize; while ((gridSize MAX_GRID_SIZE)) { cout << "SORRY, ONLY VALUES BETWEEN 1 AND " \n "; cout << "SPECIFY THE MATRIX SIZE (a positive " << "integer less than " << MAX_GRID_SIZE+1 << "): "; cin >> gridSize; } matrix grid(gridSize); for (int row=0; row<gridSize; row++) for (int col=0; col<gridSize; col++) grid.setElement(row, col, generateRandomNumber(0,9)); cout << endl << "MATRIX:" << endl << grid << endl << endl; cout << "DETERMINANT: " << grid.determinant() << endl << endl; } // The generateRandomNumber function // // randomly generates an integer in the // // range between the parameterized low- // // erBound & upperBound values (inclu- // // sive). The first time it is called, // // it seeds the rand() random number // // generation function. // int generateRandomNumber(int lowerBound, int upperBound) { static bool firstTime = true; time_t randomNumberSeed; if (firstTime) { time(&randomNumberSeed); srand(randomNumberSeed); firstTime = false; } return (lowerBound + int((upperBound - lowerBound) * (float(rand()) / RAND_MAX))); } matrix grid(gridSize); for (int row=0; row<gridSize; row++) for (int col=0; col<gridSize; col++) grid.setElement(row, col, generateRandomNumber(0,9)); cout << endl << "MATRIX:" << endl << grid << endl << endl; cout << "DETERMINANT: " << grid.determinant() << endl << endl; } // The generateRandomNumber function // // randomly generates an integer in the // // range between the parameterized low- // // erBound & upperBound values (inclu- // // sive). The first time it is called, // // it seeds the rand() random number // // generation function. // int generateRandomNumber(int lowerBound, int upperBound) { static bool firstTime = true; time_t randomNumberSeed; if (firstTime) { time(&randomNumberSeed); srand(randomNumberSeed); firstTime = false; } return (lowerBound + int((upperBound - lowerBound) * (float(rand()) / RAND_MAX))); }

CS

CS A mathematical “cousin” to recursion is the concept of induction. Step One: Prove The Base Case Formally demonstrate that it’s true for that smallest value, n 0. Step Two: Assume For Some General Case Assume that the it’s been proven true for all values through k, where k is at least n 0. Step Three: Prove For The Next Case Use the assumption that it’s been proven true for smaller cases to prove that it’s also true for k+1. When you want to prove that something is true for all integer values, beginning at a specific value n 0, perform the following steps:

CS Induction Example Theorem A:  i = 1,n i = ½n(n + 1) for all n  1. Proof (by induction): Step One (Prove for the base case): For n = 1,  i = 1,1 i = 1 = ½(1)(1 + 1). Step Two (Assume for some general case): Assume for n = k:  i = 1,k i = ½k(k + 1). Step Three (Prove for the next case): Prove for n = k + 1:  i = 1,k+1 i = (k + 1) +  i = 1,k i = (k + 1) + ½k(k + 1) (by the assumption for case k) = ½(2)(k + 1) + ½k(k + 1) = ½(k + 1)(k + 2) = ½(k + 1)((k + 1) + 1).

CS To prove that  i = 1,n i = ½n(n + 1) for all n  1, we started by proving that it was true for n = 1. Once we accomplished that, we assumed that it was true for some arbitrary value k and then proved that that made it true for the next value: k + 1. In essence, this last proof causes the truth of the theorem to “cascade” through all remaining values. Why Does Induction Work? TRUEFOR n = 1: 1 = ½(1)(2)TRUEFOR n = 1: 1 = ½(1)(2) Letting k = 1 TRUEFOR n = 2: = ½(2)(3)TRUEFOR n = 2: = ½(2)(3) Letting k = 2 TRUEFOR n = 3: = ½(3)(4)TRUEFOR n = 3: = ½(3)(4) Letting k = 3 Proof that if it’s true for n = k, then it’s also true for n = k + 1 TRUEFOR n = 4: = ½(4)(5)TRUEFOR n = 4: = ½(4)(5) Letting k = 4 TRUEFOR n = 5 : = ½(5)(6)TRUEFOR n = 5 : = ½(5)(6) And so on...

CS Theorem Z: For any group of n people, all n have the same height. What’s Wrong With This Induction? Proof (by induction): Step One (Prove for the base case): For n = 1, the group consists of a single person, so the entire group obviously has the same height. Step Two (Assume for some general case): Assume for n = k: Any group of k people have the same height. Step Three (Prove for the next case): Prove for n = k + 1: Given a group of k + 1 people, remove one person. The resulting group of k people must, by the inductive hypothesis, have the same height. Reinsert the person that was removed and then remove a different person. The resulting group of k people must also have the same height. Thus, all k + 1 people must have the same height!

CS int powerOf2(const int &n) { if (n == 0) return 1; return powerOf2(n-1) + powerOf2(n-1); } int powerOf2(const int &n) { if (n == 0) return 1; return powerOf2(n-1) + powerOf2(n-1); } One of the bridges between recursion and induction is the recurrence relation, which can be used to determine the execution time of a recursive function. Assuming that the execution time for arithmetic operations, condition checking, and returning are all the same, let’s also assume that there is a function T(n) such that it takes T(k) time to execute powerOf2(k). Examination of the code above allows us to conclude the following two facts: T(0) = 2 T(k) = 5 + 2T(k-1) for all k > 0 Using mathematical induction, we can prove that: T(k) = 7(2 k )-5 for all k  0 Step One (Prove for the base case): For n = 0, we already know that T(0) = 2, and 7(2 0 )-5 also evaluates to 2. Step One (Prove for the base case): For n = 0, we already know that T(0) = 2, and 7(2 0 )-5 also evaluates to 2. Step Two (Assume for some general case): Assume for n = k: T(k) = 7(2 k )-5. Step Two (Assume for some general case): Assume for n = k: T(k) = 7(2 k )-5. Step Three (Prove for the next case): We need to prove it for n = k + 1: We know that T(k+1) = 5 + 2T(k), and we’re assuming that T(k) = 7(2 k )-5, so we can conclude that T(k+1) = 5 + 2(7(2 k )-5) = 7(2 k+1 )-5, which is what we wanted. Step Three (Prove for the next case): We need to prove it for n = k + 1: We know that T(k+1) = 5 + 2T(k), and we’re assuming that T(k) = 7(2 k )-5, so we can conclude that T(k+1) = 5 + 2(7(2 k )-5) = 7(2 k+1 )-5, which is what we wanted.

CS int powerOf2(const int &n) { if (n == 0) return 1; return 2*powerOf2(n-1); } int powerOf2(const int &n) { if (n == 0) return 1; return 2*powerOf2(n-1); } Let’s try the same approach on this alternate form of the function. Using the same assumptions as before, we get the following recurrence relation: T(0) = 2 T(k) = 4 + T(k-1) for all k > 0 This time, however, mathematical induction tells us that: T(k) = 4k+2 for all k  0