Recursion as a Problem-Solving Technique Defining Languages Language A set of strings of symbols C++Programs = {strings s: s is a syntactically correct C++ program} Grammar States the rules of the language - the syntax For C++Programs, the syntax is not within the scope of this discussion. If the rules are recursive in nature, you can determine if a string is in the language by using a recognition algorithm. A recognition algorithm is a process for determining if a string is syntactically correct based on the rules of the language. A Simple Language: Palindromes Language Palindromes = {string s: s reads the same forwards as backwards} Grammar Characters in the string have to be considered in pairs Rules: s is a palindrome if and only if: 1. The first and last characters of s are the same 2. s minus its first and last characters is a palindrome Recognition Algorithm The set of rules above define a circular argument: you must take the result of Rule #2 and apply the rules again. This is the essence of recursion - re-application of the rules. However, you need a base case so that you know when to stop. Recursive Solution: 1. Define the problem in terms of a smaller problem of the same type See Rule #2 2. Identify how the recursive call diminishes the size of the problem The string is shorter by two characters 3. Identify the base case, the point at which the problem no longer diminishes One way to exit the recursive process comes indirectly from Rule #1: if ( Rule #1 is false ) s is not a palindrome If Rule #1 continues to be true, we need a base case. We actually have two base cases: 1. If s has an even number of characters, and Rule #1 continues to be true, we will eventually be left with an empty string. An empty string is a palindrome. 2. If s has an odd number of characters and Rule #1 continues to be true, we will eventually be left with 1 character. 1 character is a palindrome 4. Make certain that the base case can be reached Yes. The pseudocode for the recognition algorithm is: Base Cases : if ( s is an empty string or is of length 1 ) return true Recursive Call : else if ( Rule #1 is true ) return the result of Rule #2 The Test Failed: else return false What arguments do we need to pass to our recursive function? First Call: s Next Calls : s.substring(1, s.length()) A Simple Language: Algebraic Expressions Infix - expressions are evaluated based on the precedence of the operator Parentheses Exponents Multiplication Division Addition Subtraction a + b * c Prefix - the operator is applied to the two operands that follow it + a * b c One method to convert: 1. Fully parenthesize the infix expression 2. Move the operator to the position marked by its open parenthisis 3. Remove the parentheses Postfix - the operator is applied to the two operands that precede it a b c * + One method to convert: 1. Fully parenthesize the infix expression 2. Move the operator to the position marked by its closed parenthisis 3. Remove the parentheses Recursive Solution: We'll leave this as an exercise for a later class. Towers of Hanoi (Applet) Pseudocode void moveTower(disk, source, dest, spare) { if (disk == 0 ) move disk from source to dest else { moveTower(disk - 1, source, spare, dest) move disk from source to dest moveTower(disk - 1, spare, dest, source) } }