Chapter 18 recursion
Download
1 / 101

Chapter 18 Recursion - PowerPoint PPT Presentation


  • 137 Views
  • Uploaded on

Chapter 18 Recursion. Chapter Goals. To learn about the method of recursion To understand the relationship between recursion and iteration To analyze problems that are much easier to solve by recursion than by iteration To learn to "think recursively"

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Chapter 18 Recursion' - janette


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Chapter 18 recursion

Chapter 18Recursion


Chapter goals
Chapter Goals

  • To learn about the method of recursion

  • To understand the relationship between recursion and iteration

  • To analyze problems that are much easier to solve by recursion than by iteration

  • To learn to "think recursively"

  • To be able to use recursive helper methods

  • To understand when the use of recursion affects the efficiency of an algorithm


Triangle numbers
Triangle Numbers

  • Compute the area of a triangle of width n

  • Assume each [ ] square has an area of 1

  • Also called the nth triangle number

  • The third triangle number is 6[ ] [ ][ ][ ][ ][ ]


Outline of triangle class
Outline of Triangle Class

public class Triangle{ public Triangle(int aWidth) { width = aWidth; } public int getArea() { . . . } private int width;}


Handling triangle of width 1
Handling Triangle of Width 1

  • The triangle consists of a single square

  • Its area is 1

  • Add the code to getArea method for width 1

public int getArea(){ if (width == 1) return 1; . . .}


Handling the general case
Handling the General Case

  • Assume we know the area of the smaller, colored triangle

  • Area of larger triangle can be calculated as:

[] [][][][][][][][][]

smallerArea + width

Continued


Handling the general case1
Handling the General Case

  • To get the area of the smaller triangle

    • Make a smaller triangle and ask it for its area

Triangle smallerTriangle = new Triangle(width - 1);int smallerArea = smallerTriangle.getArea();


Completed getarea method
Completed getArea method

public int getArea(){ if (width == 1) return 1; Triangle smallerTriangle = new Triangle(width - 1); int smallerArea = smallerTriangle.getArea(); return smallerArea + width;}


Computing the area of a triangle with width 4
Computing the area of a triangle with width 4

  • getArea method makes a smaller triangle of width 3

    • It calls getArea on that triangle

      • That method makes a smaller triangle of width 2

        • It calls getArea on that triangle

          • That method makes a smaller triangle of width 1

          • It calls getArea on that triangle

        • That method returns 1

Continued


Computing the area of a triangle with width 41
Computing the area of a triangle with width 4

  • The method returns smallerArea + width = 1 + 2 = 3

  • The method returns smallerArea + width = 3 + 3 = 6

  • The method returns smallerArea + width = 6 + 4 = 10


  • Recursion
    Recursion

    • A recursive computation solves a problem by using the solution of the same problem with simpler values

    • For recursion to terminate, there must be special cases for the simplest inputs.

    • To complete our Triangle example, we must handle width <= 0

    if (width <= 0)  return 0;

    Continued


    Recursion1
    Recursion

    • Two key requirements for recursion success:

      • Every recursive call must simplify the computation in some way

      • There must be special cases to handle the simplest computations directly


    Other ways to compute triangle numbers
    Other Ways to Compute Triangle Numbers

    • The area of a triangle equals the sum

    • Using a simple loop:

    • Using math:

    1 + 2 + 3 + . . . + width

    double area = 0;for (int i = 1; i <= width; i++) area = area + i;

    1 + 2 + . . . + n = n × (n + 1)/2=> width * (width + 1) / 2


    File triangle java
    File Triangle.java

    01: /**

    02: A triangular shape composed of stacked unit squares like this:

    03: []

    04: [][]

    05: [][][]

    06: . . .

    07: */

    08:public class Triangle

    09:{

    10: /**

    11: Constructs a triangular shape.

    12: @param aWidth the width (and height) of the triangle

    13: */

    14:public Triangle(int aWidth)

    15: {

    16: width = aWidth;

    17: }

    Continued


    File triangle java1
    File Triangle.java

    18:

    19: /**

    20: Computes the area of the triangle.

    21: @return the area

    22: */

    23:public int getArea()

    24: {

    25:if (width <= 0) return0;

    26:if (width == 1) return1;

    27: Triangle smallerTriangle = new Triangle(width - 1);

    28:int smallerArea = smallerTriangle.getArea();

    29:return smallerArea + width;

    30: }

    31:

    32:private int width;

    33:}


    File triangletester java
    File TriangleTester.java

    01:import java.util.Scanner;

    02:

    03:public class TriangleTester

    04:{

    05:public static void main(String[] args)

    06: {

    07: Scanner in = new Scanner(System.in);

    08: System.out.print("Enter width: ");

    09:int width = in.nextInt();

    10: Triangle t = new Triangle(width);

    11:int area = t.getArea();

    12: System.out.println("Area = " + area);

    13: }

    14:}

    Continued


    File triangle java2
    File triangle.java

    Output

    Enter width: 10

    Area = 55


    Self check
    Self Check

    • Why is the statement in the getArea method unnecessary?

    • How would you modify the program to recursively compute the area of a square?

    if (width == 1) return 1;


    Answers
    Answers

    • Suppose we omit the statement. When computing the area of a triangle with width 1, we compute the area of the triangle with width 0 as 0, and then add 1, to arrive at the correct area.

    Continued


    Answers1
    Answers

    • You would compute the smaller area recursively, then return [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Of course, it would be simpler to compute

    smallerArea + width + width - 1.


    Permutations
    Permutations

    • Design a class that will list all permutations of a string

    • A permutation is a rearrangement of the letters

    • The string "eat" has six permutations "eat" "eta" "aet" "tea" "tae"


    Public interface of permutationgenerator
    Public Interface of PermutationGenerator

    public class PermutationGenerator{ public PermutationGenerator(String aWord) { . . . } ArrayList<String> getPermutations() { . . . }}


    File permutationgeneratortester java
    File PermutationGeneratorTester.java

    01:import java.util.ArrayList;

    02:

    03: /**

    04: This program tests the permutation generator.

    05: */

    06:public class PermutationGeneratorTester

    07:{

    08:public static void main(String[] args)

    09:{

    10:PermutationGenerator generator

    11:= new PermutationGenerator("eat");

    12:ArrayList<String> permutations = generator.getPermutations();

    13:for (String s : permutations)

    14:{

    15:System.out.println(s);

    16:}

    Continued


    File permutationgeneratortester java1
    File PermutationGeneratorTester.java

    17: }

    18: }

    19:


    File permutationgeneratortester java2
    File PermutationGeneratorTester.java

    Output

    eatetaaetateteatae


    To generate all permutations
    To Generate All Permutations

    • Generate all permutations that start with 'e' , then 'a' then 't'

    • To generate permutations starting with 'e', we need to find all permutations of "at"

    • This is the same problem with simpler inputs.

    • Use recursion


    To generate all permutations1
    To Generate All Permutations

    • getPermutations: loop through all positions in the word to be permuted

    • For each position, compute the shorter word obtained by removing ith letter:

    String shorterWord = word.substring(0, i) + word.substring(i + 1);

    Continued


    To generate all permutations2
    To Generate All Permutations

    • Construct a permutation generator to get permutations of the shorter word

    PermutationGenerator shorterPermutationGenerator = new PermutationGenerator(shorterWord);ArrayList<String> shorterWordPermutations = shorterPermutationGenerator.getPermutations();


    To generate all permutations3
    To Generate All Permutations

    • Finally, add the removed letter to front of all permutations of the shorter word

    • Special case: simplest possible string is the empty string; single permutation, itself

    for (String s : shorterWordPermutations){ result.add(word.charAt(i) + s);}


    File permutationgenerator java
    File PermutationGenerator.java

    01:import java.util.ArrayList;

    02:

    03: /**

    04: This class generates permutations of a word.

    05: */

    06:public class PermutationGenerator

    07:{

    08: /**

    09: Constructs a permutation generator.

    10: @param aWord the word to permute

    11: */

    12:public PermutationGenerator(String aWord)

    13: {

    14: word = aWord;

    15: }

    16:

    Continued


    File permutationgenerator java1
    File PermutationGenerator.java

    17: /**

    18: Gets all permutations of a given word.

    19: */

    20:public ArrayList<String> getPermutations()

    21: {

    22: ArrayList<String> result = new ArrayList<String>();

    23:

    24:// The empty string has a single permutation: itself

    25:if (word.length() == 0)

    26: {

    27: result.add(word);

    28:return result;

    29: }

    30:

    31: // Loop through all character positions

    32:for (int i = 0; i < word.length(); i++)

    33: {

    Continued


    File permutationgenerator java2
    File PermutationGenerator.java

    34: // Form a simpler word by removing the ith character

    35:String shorterWord = word.substring(0, i)

    36: + word.substring(i + 1);

    37:

    38: // Generate all permutations of the simpler word

    39: PermutationGenerator shorterPermutationGenerator

    40: = new PermutationGenerator(shorterWord);

    41: ArrayList<String> shorterWordPermutations

    42: = shorterPermutationGenerator.getPermutations();

    43:

    44: // Add the removed character to the front of

    45: // each permutation of the simpler word,

    46:for (String s : shorterWordPermutations)

    47: {

    48: result.add(word.charAt(i) + s);

    49: }

    50: }

    Continued


    File permutationgenerator java3
    File PermutationGenerator.java

    51: // Return all permutations

    52:return result;

    53: }

    54:

    55:private String word;

    56:}


    Self check1
    Self Check

    • What are all permutations of the four-letter word beat?

    • Our recursion for the permutation generator stops at the empty string. What simple modification would make the recursion stop at strings of length 0 or 1?


    Answers2
    Answers

    • They are b followed by the six permutations of eat, efollowed by the six permutations of bat, a followed by the six permutations of bet, and t followed by the six permutations of bea.

    • Simply changebecause a word with a single letter is also its sole permutation.

    if (word.length() == 0) to if (word.length() <= 1)


    Tracing through recursive methods
    Tracing Through Recursive Methods

    Figure 1:Debugging a Recursive Method


    Thinking recursively
    Thinking Recursively

    • Problem: test whether a sentence is a palindrome

    • Palindrome: a string that is equal to itself when you reverse all characters

      • A man, a plan, a canal–Panama!

      • Go hang a salami, I'm a lasagna hog

      • Madam, I'm Adam


    Implement ispalindrome method
    Implement isPalindrome Method

    public class Sentence{ /** Constructs a sentence. @param aText a string containing all characters of

    the sentence */ public Sentence(String aText) { text = aText; }

    Continued


    Implement ispalindrome method1
    Implement isPalindrome Method

    /** Tests whether this sentence is a palindrome. @return true if this sentence is a palindrome,

    false otherwise */ public boolean isPalindrome() { . . . } private String text;

    }


    Thinking recursively step by step
    Thinking Recursively: Step-by-Step

    • Consider various ways to simplify inputs Here are several possibilities:

      • Remove the first character

      • Remove the last character

      • Remove both the first and last characters

      • Remove a character from the middle


    Thinking recursively step by step1
    Thinking Recursively: Step-by-Step

    • Combine solutions with simpler inputs into a solution of the original problem

      • Most promising simplification: remove first and last characters "adam, I'm Ada", is a palindrome too!

      • Thus, a word is a palindrome if

        • The first and last letters match, and

        • Word obtained by removing the first and last letters is a palindrome

    Continued


    Thinking recursively step by step2
    Thinking Recursively: Step-by-Step

    • Combine solutions with simpler inputs into a solution of the original problem

      • What if first or last character is not a letter? Ignore it

        • If the first and last characters are letters, check whether they match; if so, remove both and test shorter string

        • If last character isn't a letter, remove it and test shorter string

        • If first character isn't a letter, remove it and test shorter string


    Thinking recursively step by step3
    Thinking Recursively: Step-by-Step

    • Find solutions to the simplest inputs

      • Strings with two characters

        • No special case required; step two still applies

      • Strings with a single character

        • They are palindromes

      • The empty string

        • It is a palindrome


    Thinking recursively step by step4
    Thinking Recursively: Step-by-Step

    • Implement the solution by combining the simple cases and the reduction step

    public boolean isPalindrome()

    {

    int length = text.length();

    // Separate case for shortest strings.

    if (length <= 1) return true;

    // Get first and last characters, converted to lowercase.

    char first = Character.toLowerCase(text.charAt(0));

    char last = Character.toLowerCase(text.charAt(length - 1));

    Continued


    Thinking recursively step by step5
    Thinking Recursively: Step-by-Step

    if (Character.isLetter(first) && Character.isLetter(last))

    {

    // Both are letters.

    if (first == last)

    {

    // Remove both first and last character.

    Sentence shorter

    = new Sentence(text.substring(1, length - 1));

    return shorter.isPalindrome();

    }

    else

    return false;

    }

    Continued


    Thinking recursively step by step6
    Thinking Recursively: Step-by-Step

    else if (!Character.isLetter(last))

    {

    // Remove last character.

    Sentence shorter

    = new Sentence(text.substring(0, length - 1));

    return shorter.isPalindrome();

    }

    else

    {

    // Remove first character.

    Sentence shorter = new Sentence(text.substring(1));

    return shorter.isPalindrome();

    }

    }


    Recursive helper methods
    Recursive Helper Methods

    • Sometimes it is easier to find a recursive solution if you make a slight change to the original problem

    • Consider the palindrome test of previous slide It is a bit inefficient to construct new Sentence objects in every step

    Continued


    Recursive helper methods1
    Recursive Helper Methods

    • Rather than testing whether the sentence is a palindrome, check whether a substring is a palindrome:

    /** Tests whether a substring of the sentence is a palindrome. @param start the index of the first character of the substring @param end the index of the last character of the substring @return true if the substring is a palindrome*/public boolean isPalindrome(int start, int end)


    Recursive helper methods2
    Recursive Helper Methods

    • Then, simply call the helper method with positions that test the entire string:

    public boolean isPalindrome(){ return isPalindrome(0, text.length() - 1);}


    Recursive helper methods ispalindrome
    Recursive Helper Methods:isPalindrome

    public boolean isPalindrome(int start, int end)

    {

    // Separate case for substrings of length 0 and 1.

    if (start >= end) return true;

    // Get first and last characters, converted to lowercase.

    char first = Character.toLowerCase(text.charAt(start));

    char last = Character.toLowerCase(text.charAt(end));

    Continued


    Recursive helper methods ispalindrome1
    Recursive Helper Methods:isPalindrome

    if (Character.isLetter(first) && Character.isLetter(last))

    {

    if (first == last)

    {

    // Test substring that doesn’t contain the

    matching letters.

    return isPalindrome(start + 1, end - 1);

    }

    else

    return false;

    }

    else if (!Character.isLetter(last))

    {

    // Test substring that doesn’t contain the last character.

    return isPalindrome(start, end - 1);

    }

    Continued


    Recursive helper methods ispalindrome2
    Recursive Helper Methods:isPalindrome

    else

    {

    // Test substring that doesn’t contain the first character.

    return isPalindrome(start + 1, end);

    }

    }


    Self check2
    Self Check

    • Do we have to give the same name to both isPalindrome methods?

    • When does the recursive isPalindrome method stop calling itself?


    Answers3
    Answers

    • No–the first one could be given a different name such as substringIsPalindrome.

    • When start >= end, that is, when the investigated string is either empty or has length 1.


    Fibonacci sequence
    Fibonacci Sequence

    • Fibonacci sequence is a sequence of numbers defined by

    • First ten terms

    1, 1, 2, 3, 5, 8, 13, 21, 34, 55


    File fibtester java
    File FibTester.java

    01:import java.util.Scanner;

    02:

    03: /**

    04: This program computes Fibonacci numbers using a recursive

    05: method.

    06: */

    07:public class FibTester

    08:{

    09:public static void main(String[] args)

    10: {

    11: Scanner in = new Scanner(System.in);

    12: System.out.print("Enter n: ");

    13:int n = in.nextInt();

    14:

    15:for (int i = 1; i <= n; i++)

    16: {

    Continued


    File fibtester java1
    File FibTester.java

    17:long f = fib(i);

    18: System.out.println("fib(" + i + ") = " + f);

    19: }

    20: }

    21:

    22: /**

    23: Computes a Fibonacci number.

    24: @param n an integer

    25: @return the nth Fibonacci number

    26: */

    27:public staticlong fib(int n)

    28: {

    29:if (n <= 2) return1;

    30:else return fib(n - 1) + fib(n - 2);

    31: }

    32:}

    Continued


    File permutationgeneratortester java3
    File PermutationGeneratorTester.java

    Output

    Enter n: 50 fib(1) = 1 fib(2) = 1 fib(3) = 2

    fib(4) = 3

    fib(5) = 5 fib(6) = 8 fib(7) = 13 . . . fib(50) = 12586269025


    The efficiency of recursion
    The Efficiency of Recursion

    • Recursive implementation of fib is straightforward

    • Watch the output closely as you run the test program

    • First few calls to fib are quite fast

    • For larger values, the program pauses an amazingly long time between outputs

    • To find out the problem, lets insert trace messages


    File fibtrace java
    File FibTrace.java

    01:import java.util.Scanner;

    02:

    03: /**

    04: This program prints trace messages that show how often the

    05: recursive method for computing Fibonacci numbers calls itself.

    06: */

    07:public class FibTrace

    08:{

    09:public static void main(String[] args)

    10: {

    11: Scanner in = new Scanner(System.in);

    12: System.out.print("Enter n: ");

    13:int n = in.nextInt();

    14:

    15:long f = fib(n);

    16:

    17: System.out.println("fib(" + n + ") = " + f);

    18: }

    Continued


    File fibtrace java1
    File FibTrace.java

    19:

    20: /**

    21: Computes a Fibonacci number.

    22: @param n an integer

    23: @return the nth Fibonacci number

    24: */

    25:public static long fib(int n)

    26: {

    27: System.out.println("Entering fib: n = " + n);

    28:long f;

    29:if (n <= 2) f = 1;

    30:else f = fib(n - 1) + fib(n - 2);

    31: System.out.println("Exiting fib: n = " + n

    32: + " return value = " + f);

    33:return f;

    34: }

    35:}


    File fibtrace java2
    File FibTrace.java

    Output

    Enter n: 6

    Entering fib: n = 6

    Entering fib: n = 5

    Entering fib: n = 4

    Entering fib: n = 3

    Entering fib: n = 2

    Exiting fib: n = 2 return value = 1

    Entering fib: n = 1

    Exiting fib: n = 1 return value = 1

    Exiting fib: n = 3 return value = 2

    Entering fib: n = 2

    Exiting fib: n = 2 return value = 1

    Exiting fib: n = 4 return value = 3

    Continued


    File fibtrace java3
    File FibTrace.java

    Entering fib: n = 3

    Entering fib: n = 2

    Exiting fib: n = 2 return value = 1

    Entering fib: n = 1

    Exiting fib: n = 1 return value = 1

    Exiting fib: n = 3 return value = 2

    Exiting fib: n = 5 return value = 5

    Entering fib: n = 4

    Entering fib: n = 3

    Entering fib: n = 2

    Exiting fib: n = 2 return value = 1

    Entering fib: n = 1

    Exiting fib: n = 1 return value = 1

    Exiting fib: n = 3 return value = 2

    Entering fib: n = 2

    Exiting fib: n = 2 return value = 1

    Exiting fib: n = 4 return value = 3

    Exiting fib: n = 6 return value = 8

    fib(6) = 8


    Call tree for computing fib 6
    Call Tree for Computing fib(6)

    Figure 2:Call Tree of the Recursive fib method


    The efficiency of recursion1
    The Efficiency of Recursion

    • Method takes so long because it computes the same values over and over

    • The computation of fib(6) calls fib(3) three times

    • Imitate the pencil-and-paper process to avoid computing the values more than once


    File fibloop java
    File FibLoop.java

    01:import java.util.Scanner;

    02:

    03: /**

    04: This program computes Fibonacci numbers using an

    // iterative method.

    05: */

    06:public class FibLoop

    07:{

    08:public static void main(String[] args)

    09: {

    10: Scanner in = new Scanner(System.in);

    11: System.out.print("Enter n: ");

    12:int n = in.nextInt();

    13:

    14:for (int i = 1; i <= n; i++)

    15: {

    Continued


    File fibloop java1
    File FibLoop.java

    16:long f = fib(i);

    17: System.out.println("fib(" + i + ") = " + f);

    18: }

    19: }

    20:

    21: /**

    22: Computes a Fibonacci number.

    23: @param n an integer

    24: @return the nth Fibonacci number

    25: */

    26:public static long fib(int n)

    27: {

    28:if (n <= 2) return1;

    29:long fold = 1;

    30:long fold2 = 1;

    31:long fnew = 1;

    32:for (int i = 3; i <= n; i++)

    33: {

    Continued


    File fibloop java2
    File FibLoop.java

    34: fnew = fold + fold2;

    35: fold2 = fold;

    36: fold = fnew;

    37: }

    38:return fnew;

    39: }

    40:}


    File permutationgeneratortester java4
    File PermutationGeneratorTester.java

    Output

    Enter n: 50

    fib(1) = 1

    fib(2) = 1

    fib(3) = 2

    fib(4) = 3

    fib(5) = 5

    fib(6) = 8

    fib(7) = 13

    . . .

    fib(50) = 12586269025


    The efficiency of recursion2
    The Efficiency of Recursion

    • Occasionally, a recursive solution runs much slower than its iterative counterpart

    • In most cases, the recursive solution is only slightly slower

    • The iterative isPalindromeperforms only slightly better than recursive solution

      • Each recursive method call takes a certain amount of processor time


    The efficiency of recursion3
    The Efficiency of Recursion

    • Smart compilers can avoid recursive method calls if they follow simple patterns

    • Most compilers don't do that

    • In many cases, a recursive solution is easier to understand and implement correctly than an iterative solution

    • "To iterate is human, to recurse divine.", L. Peter Deutsch


    Iterative ispalindrome method
    Iterative isPalindrome Method

    public boolean isPalindrome()

    {

    int start = 0;

    int end = text.length() - 1; while (start < end)

    {

    char first = Character.toLowerCase(text.charAt(start));

    char last = Character.toLowerCase(text.charAt(end);

    if (Character.isLetter(first) && Character.isLetter(last))

    {

    // Both are letters. if (first == last)

    {

    start++; end--;

    }

    Continued


    Iterative ispalindrome method1
    Iterative isPalindrome Method

    else return false;

    }

    if (!Character.isLetter(last)) end--;

    if (!Character.isLetter(first)) start++;

    }

    return true;

    }


    Self check3
    Self Check

    • You can compute the factorial function either with a loop, using the definition that n! = 1 × 2 × . . . × n, or recursively, using the definition that 0! = 1 and n! = (n - 1)! × n. Is the recursive approach inefficient in this case?

    • Why isn't it easy to develop an iterative solution for the permutation generator?


    Answers4
    Answers

    • No, the recursive solution is about as efficient as the iterative approach. Both require n - 1 multiplications to compute n!.

    Continued


    Answers5
    Answers

    • An iterative solution would have a loop whose body computes the next permutation from the previous ones. But there is no obvious mechanism for getting the next permutation. For example, if you already found permutations eat, eta, and aet, it is not clear how you use that information to get the next permutation. Actually, there is an ingenious mechanism for doing just that, but it is far from obvious–see Exercise P18.12.


    The limits of computation
    The Limits of Computation

    Figure 3:Alan Turing


    The limits of computation1
    The Limits of Computation

    Figure 4:A Turing Machine


    Using mutual recursions
    Using Mutual Recursions

    • Problem: to compute the value of arithmetic expressions such as

    • Computing expression is complicated

      • * and / bind more strongly than + and -

      • parentheses can be used to group subexpressions

    3 + 4 * 5(3 + 4) * 51 - (2 - (3 - (4 - 5)))


    Syntax diagram for evaluating an expression
    Syntax Diagram for Evaluating an Expression

    Figure 5:Syntax Diagrams for Evaluating an Expression


    Using mutual recursions1
    Using Mutual Recursions

    • An expression can broken down into a sequence of terms, separated by + or -

    • Each term is broken down into a sequence of factors, separated by * or /

    • Each factor is either a parenthesized expression or a number

    • The syntax trees represent which operations should be carried out first


    Syntax tree for two expressions
    Syntax Tree for Two Expressions

    Figure 6:Syntax Trees for Two Expressions


    Mutually recursive methods
    Mutually Recursive Methods

    • In a mutual recursion, a set of cooperating methods calls each other repeatedly

    • To compute the value of an expression, implement 3 methods that call each other recursively

      • getExpressionValue

      • getTermValue

      • getFactorValue


    The getexpressionvalue method
    The getExpressionValue Method

    public int getExpressionValue(){ int value = getTermValue(); boolean done = false; while (!done) { String next = tokenizer.peekToken(); if ("+".equals(next) || "-".equals(next)) { tokenizer.nextToken(); // Discard "+" or "-" int value2 = getTermValue(); if ("+".equals(next)) value = value + value2; else value = value - value2; } else done = true; } return value;}


    The getfactorvalue method
    The getFactorValue Method

    public int getFactorValue(){ int value; String next = tokenizer.peekToken(); if ("(".equals(next)) { tokenizer.nextToken(); // Discard "(" value = getExpressionValue(); tokenizer.nextToken(); // Discard ")" } else value = Integer.parseInt(tokenizer.nextToken()); return value;}


    Using mutual recursions2
    Using Mutual Recursions

    • To see the mutual recursion clearly, trace through the expression (3+4)*5:

    • getExpressionValue calls getTermValue

      • getTermValue calls getFactorValue

        • getFactorValue consumes the ( input

        • getFactorValue calls getExpressionValue

          • getExpressionValue returns eventually with the value of 7, having consumed 3 + 4. This is the recursive call.

        • getFactorValue consumes the ) input

        • getFactorValuereturns 7

    Continued


    Using mutual recursions3
    Using Mutual Recursions

    • getTermValue consumes the inputs * and 5 and returns 35

  • getExpressionValue returns 35


  • File evaluator java
    File Evaluator.java

    01: /**

    02: A class that can compute the value of an arithmetic

    expression.

    03: */

    04:public class Evaluator

    05:{

    06: /**

    07: Constructs an evaluator.

    08: @param anExpression a string containing the expression

    09: to be evaluated

    10: */

    11:public Evaluator(String anExpression)

    12: {

    13: tokenizer = new ExpressionTokenizer(anExpression);

    14: }

    15:

    Continued


    File evaluator java1
    File Evaluator.java

    16: /**

    17: Evaluates the expression.

    18: @return the value of the expression.

    19: */

    20:public int getExpressionValue()

    21: {

    22:int value = getTermValue();

    23:boolean done = false;

    24:while (!done)

    25: {

    26: String next = tokenizer.peekToken();

    27:if ("+".equals(next) || "-".equals(next))

    28: {

    29: tokenizer.nextToken(); // Discard "+" or "-"

    30:int value2 = getTermValue();

    31:if ("+".equals(next)) value = value + value2;

    32:else value = value - value2;

    33: }

    Continued


    File evaluator java2
    File Evaluator.java

    34:else done = true;

    35: }

    36:return value;

    37: }

    38:

    39: /**

    40: Evaluates the next term found in the expression.

    41: @return the value of the term

    42: */

    43:public int getTermValue()

    44: {

    45:int value = getFactorValue();

    46:boolean done = false;

    47:while (!done)

    48: {

    49: String next = tokenizer.peekToken();

    50:if ("*".equals(next) || "/".equals(next))

    51: {

    Continued


    File evaluator java3
    File Evaluator.java

    52: tokenizer.nextToken();

    53:int value2 = getFactorValue();

    54:if ("*".equals(next)) value = value * value2;

    55:else value = value / value2;

    56: }

    57:else done = true;

    58: }

    59:return value;

    60: }

    61:

    62: /**

    63: Evaluates the next factor found in the expression.

    64: @return the value of the factor

    65: */

    Continued


    File evaluator java4
    File Evaluator.java

    66:public int getFactorValue()

    67: {

    68:int value;

    69: String next = tokenizer.peekToken();

    70:if ("(".equals(next))

    71: {

    72: tokenizer.nextToken(); // Discard "("

    73: value = getExpressionValue();

    74: tokenizer.nextToken(); // Discard ")"

    75: }

    76:else

    77: value = Integer.parseInt(tokenizer.nextToken());

    78:return value;

    79: }

    80:

    81:private ExpressionTokenizer tokenizer;

    82:}


    File expressiontokenizer java
    File ExpressionTokenizer.java

    01: /**

    02: This class breaks up a string describing an expression

    03: into tokens: numbers, parentheses, and operators.

    04: */

    05:public class ExpressionTokenizer

    06:{

    07: /**

    08: Constructs a tokenizer.

    09: @param anInput the string to tokenize

    10: */

    11:public ExpressionTokenizer(String anInput)

    12: {

    13: input = anInput;

    14: start = 0;

    15: end = 0;

    16: nextToken();

    17: }

    Continued


    File expressiontokenizer java1
    File ExpressionTokenizer.java

    18:

    19: /**

    20: Peeks at the next token without consuming it.

    21: @return the next token or null if there are no

    // more tokens

    22: */

    23:public String peekToken()

    24: {

    25:if (start >= input.length()) return null;

    26:else return input.substring(start, end);

    27: }

    28:

    29: /**

    30: Gets the next token and moves the tokenizer to

    // the following token.

    31: @return the next token or null if there are no

    // more tokens

    32: */

    Continued


    File expressiontokenizer java2
    File ExpressionTokenizer.java

    33:public String nextToken()

    34: {

    35: String r = peekToken();

    36: start = end;

    37:if (start >= input.length()) return r;

    38:if (Character.isDigit(input.charAt(start)))

    39: {

    40: end= start + 1;

    41:while (end < input.length()

    42: && Character.isDigit(input.charAt(end)))

    43: end++;

    44: }

    45:else

    46: end = start + 1;

    47:return r;

    48: }

    Continued


    File expressiontokenizer java3
    File ExpressionTokenizer.java

    50:private String input;

    51:private int start;

    52:private int end;

    53:}


    File evaluatortester java
    File EvaluatorTester.java

    01:import java.util.Scanner;

    02:

    03: /**

    04: This program tests the expression evaluator.

    05: */

    06:public class EvaluatorTester

    07:{

    08:public static void main(String[] args)

    09:{

    10:Scanner in = new Scanner(System.in);

    11:System.out.print("Enter an expression: ");

    12:String input = in.nextLine();

    13:Evaluator e = new Evaluator(input);

    14:int value = e.getExpressionValue();

    15:System.out.println(input + "=" + value);

    16:}

    17:}

    Continued


    File evaluatortester java1
    File EvaluatorTester.java

    • Output

    Enter an expression: 3+4*5 3+4*5=23


    Self check4
    Self Check

    • What is the difference between a term and a factor? Why do we need both concepts?

    • Why does the expression parser use mutual recursion?

    • What happens if you try to parse the illegal expression 3+4*)5? Specifically, which method throws an exception?


    Answers6
    Answers

    • Factors are combined by multiplicative operators (*and /), terms are combined by additive operators (+, -). We need both so that multiplication can bind more strongly than addition.

    • To handle parenthesized expressions, such as 2+3*(4+5). The subexpression 4+5 is handled by a recursive call to getExpressionValue.

    Continued


    Answers7
    Answers

    • The Integer.parseInt call ingetFactorValuethrows an exception when it is given the string ")".