You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: source/ch7_recursion.ptx
+38-23Lines changed: 38 additions & 23 deletions
Original file line number
Diff line number
Diff line change
@@ -12,13 +12,31 @@
12
12
<p><idx>recursion</idx>
13
13
As you may know from Python, <term>recursion</term> is a powerful problem-solving technique involving base cases and recursive steps in which a function or method calls itself. When moving to Java, the core logic you've learned remains identical. The challenge is adapting that logic to Java's statically-typed, class-based syntax.
14
14
</p>
15
+
16
+
<p>
17
+
Let's take the familiar factorial function, which calculates <m>n!</m> (read as "n factorial"), so for example 5! = 5 × 4 × 3 × 2 × 1 = 120. Factorial is a classic example of recursion, where the function calls itself with a smaller value until it reaches a base case.
18
+
In general, <m>n! = n \times (n-1) \times (n-2) \times \cdots \times 2 \times 1</m>,
19
+
or recursively defined as <m>n! = n \times (n-1)!</m> with base cases <m>0! = 1</m> and <m>1! = 1</m>.
20
+
</p>
21
+
<p>
22
+
You may recall mathematical notation using the symbol <m>\sum</m> (Greek letter sigma)
23
+
to represent "sum." For example, when we sum all elements in an array, we write
24
+
<m>\sum_{i=0}^{n-1} a_i</m>, where <m>i=0</m> below the symbol indicates we start at index 0,
25
+
<m>n-1</m> above it means we end at index <m>n-1</m>, and <m>a_i</m> represents the array
26
+
element at each index <m>i</m>. Similarly, <m>\sum_{i=1}^{n} i</m> means "sum all integers
27
+
<m>i</m> from 1 to <m>n</m>."
28
+
</p>
29
+
<p>
30
+
Factorial involves multiplication rather than addition, so we use the product symbol
31
+
<m>\prod</m> (Greek letter pi): <m>n! = \prod_{i=1}^{n} i</m>, which means "multiply
32
+
all integers <m>i</m> from 1 to <m>n</m>." Both summation and factorial can be expressed
33
+
recursively—summation as the first element plus the sum of remaining elements, and factorial
34
+
as <m>n \times (n-1)!</m>.
35
+
</p>
15
36
<p>
16
-
Let's take the familiar factorial function (which calculates the factorial of a number, namely the product of all positive integers from 1 to n). The logical steps in the code are the same, but the implementation details change.
17
-
</p>
18
-
<p>
19
-
Here is a Python implementation using functions:
37
+
Here is a Python implementation of factorial using functions:
Many Python programs organize related functions into classes. The same factorial function can be placed inside a class as a method. Then you need to create an instance of the class to call the method. There we create the class <c>MathTools</c> with a method <c>factorial</c>, and we call it from the <c>main</c> function.
In many recursive algorithms, the recursive calls need extra information that the original caller shouldn't have to provide. For example, to recursively process an array, you need to keep track of the current position (index). This extra information clutters the public-facing method signature and forces users to provide implementation details they shouldn't need to know about.
126
+
In many recursive algorithms, the recursive calls need extra information that the original caller shouldn't have to provide. For example, to recursively process an array, you need to keep track of the index of the current position. This extra information clutters the public-facing signature by forcing users to provide implementation details they shouldn't actually need to know about.
109
127
</p>
110
128
<p><idx>helper method pattern in recursion</idx>
111
-
A common pattern to solve this is using a <term>helper method</term>. This pattern lets you create a clean, simple public method that users will call, while the private helper method handles the complex details of the recursion. The public method typically makes the initial call to the private helper, providing the necessary starting values for the extra parameters.
112
-
</p>
113
-
<p>
114
-
Let's see this pattern in action with an example that calculates the sum of all elements in an integer array. Notice how the public method only requires the array, but the recursive logic needs to track the current index position.
129
+
A common pattern to solve this problem is by using a <term>helper method</term>. This pattern lets you create a clean, simple function or public method that users can call, while the private helper function or method handles the complex details of the recursion. The function or public method typically makes an initial call to the private helper method or function, providing the necessary starting values for the extra parameters.
115
130
</p>
131
+
116
132
117
133
<p>
118
134
First, let's see what happens if we try to write a recursive array sum function <em>without</em> using a helper method. In this approach, the user must provide the starting index, which is awkward and exposes implementation details:
This approach has several problems: users must remember to start with index 0, the method signature is cluttered with implementation details, and it's easy to make mistakes by passing the wrong starting index. The same awkward pattern appears in Java:
163
+
This approach has a significant problem, namely that users must remember to start with index 0. Hence, the method signature is cluttered with an implementation detail, and it's easy to make a mistake by passing the wrong starting index. The same awkward pattern appears in Java:
public static int sumArray(int[] arr, int index) {
@@ -170,13 +186,12 @@ public class ArrayProcessor {
170
186
</program>
171
187
172
188
<p>
173
-
Both versions force users to understand and provide implementation details they shouldn't need to know about. Now let's see how helper methods solve this problem by providing a clean, user-friendly interface.
189
+
Both versions force users to understand and provide implementation details they shouldn't need to know about. Now let's see how helper methods solve this problem by providing a clean, user-friendly interface. Notice how the public method only requires the array itself, and the hidden recursive logic tracks the current index position.
174
190
</p>
175
-
176
191
<p>
177
192
Here's the improved Python version using a helper method:
The key insight here is called the <term>separation of concerns</term>. The public <c>sum_array</c> method provides a user-friendly interface—callers just pass an array and get the sum. They don't need to know about indexes or how the recursion works internally. The private <c>_sum_helper</c> method handles the recursive logic with the extra parameter needed to track progress through the array.
230
+
The key insight here is called the <term>separation of concerns</term>. The public <c>sum_array</c> method provides a user-friendly interface—callers just pass an array and get the sum. Users don't need to know about indexes or how the recursion works internally. The private <c>_sum_helper</c> method handles the recursive logic with the extra parameter needed to track progress through the array.
216
231
</p>
217
232
218
233
<p>
219
234
Now let's see the improved Java version using a helper method:
This helper method pattern is essential when your recursive algorithm needs to track additional state (like array positions, accumulated values, or depth counters) that the original caller shouldn't need to provide. It's a fundamental technique you'll use frequently in recursive problem solving.
272
+
This helper method pattern is essential when your recursive algorithm needs to track additional state (like array positions, accumulated values, or depth counters) that the original caller shouldn't need to provide or care about. It's a fundamental pattern and technique you'll likely use frequently in recursive problem solving.
258
273
</p>
259
274
</section>
260
275
@@ -276,7 +291,7 @@ public class ArrayProcessor {
276
291
<p>
277
292
The following Python code demonstrates a situation where a function calls itself indefinitely without a base case, leading to aRecursionError.
The following Java code demonstrates a similar situation, where a method calls itself indefinitely without a base case, leading to a StackOverflowError.
0 commit comments