Skip to content

Commit b1c02c4

Browse files
authored
update: added memo and results section
1 parent 94c8850 commit b1c02c4

File tree

1 file changed

+65
-3
lines changed
  • allhands/spring2025/weekeleven/teamthree

1 file changed

+65
-3
lines changed

allhands/spring2025/weekeleven/teamthree/index.qmd

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,48 @@ TODO: Duru- please explain your approach, including a code sample
2626

2727
### Generate Fibonacci using a Memoized approach
2828

29-
TODO: Titus- please explain your approach, including a code sample
29+
This implementation uses a concept we previously discussed in a class session: memoization.
30+
Memoization is a technique that stores previously computed values to avoid redundant
31+
calculations. Our implementation checks if `n` has already been computed, and if so,
32+
it retrieves the value from memo, which saves on computation time. It uses a recursive
33+
approach to calculate the fibonacci value, but importantly it stores the result in
34+
a dictionary `memo` to prevent recalculating the same values multiple times on future
35+
runs. This approach is particularly valuable for algorithms that exhibit overlapping
36+
problems, or frequent use of similar calculations. Without memoization, recursive calls
37+
can lead to exponential time complexity, making computations infeasible for large inputs.
38+
However, by using a memoized approach and storing/reusing results, we found that our program
39+
is more efficient as `n` increases.
40+
41+
Below I have included a section of this approach:
42+
43+
```python
44+
def fibonacci_generator(n: int, memo: Dict[int, int]) -> int:
45+
"""Generates the Fibonacci sequence up to the nth term using memoization."""
46+
# initialize a dictionary to store previously computed numbers.
47+
if memo is None:
48+
memo = {}
49+
# if the number has already been calculated, use it
50+
if n in memo:
51+
return memo[n]
52+
# create the base case for handling 1 & 2 fibonacci numbers
53+
base_case = 2
54+
if n < base_case:
55+
return n
56+
# calculate the fibonacci for nth number
57+
memo[n] = fibonacci_generator(n - 1, memo) + fibonacci_generator(
58+
n - 2, memo
59+
)
60+
# return the appropriate fibonacci number
61+
return memo[n]
62+
```
63+
64+
As you can see in the above code, this memoized approach takes in a possible dictionary,
65+
`memo` and stores already computed results in said dictionary. Then, when computing the
66+
fibonacci number, it first looks to see if it was already calculated, then if not, it performs
67+
a recursive approach to find the value. This approach, as mentioned before, allows for faster
68+
time complexity, especially as the number of runs increases and previously calculated results
69+
are already store. However, it is still important to understand and weight the trade-off of time
70+
complexity and memory usage when considering a memoized approach.
3071

3172
### Generate Fibonacci using an Iterative approach
3273

@@ -146,7 +187,28 @@ This is a chart using the values in the `Averages` table above, for the Recursiv
146187

147188
# Results
148189

149-
TODO: Titus to complete
190+
Our results from running our Fibonacci sequence experiments, using iterative, recursive, and
191+
memoized approaches show clear performance differences, with respect to time. The iterative
192+
method consistently performed the fastest across all test cases, with an average runtime of
193+
`0.000017121 sec` with our largest experiment input. This shows that even as the sequence size
194+
increased, the iterative approach maintained its efficiency, proving a worst case time complexity
195+
of $O(n)$. In contrast, the recursive approach showed exponential time complexity $O(2^n)$,
196+
as our execution times skyrocket as the sequence size grew. While manageable for small inputs,
197+
the recursive method is impractical for larger Fibonacci numbers, as seen in the drastic jump to
198+
execution times. Our results highlight the inefficiency of recursion, which can be attributed
199+
to redundant calculations and the cost associated with function call overhead.
200+
201+
The memoized approach, which optimizes recursion by storing previously computed values, improved
202+
performance over the recursive approach. While not as fast as the iterative approach, memoization
203+
reduced run time compared to recursion, with an average runtime of `0.000111318 sec` with our largest
204+
experimental input. Interestingly, if you view the above image highlight the time complexity of each approach,
205+
you will notice as the values increase for the memoization, you begin to see a plateau, showing that an
206+
increase in previously calculated results starts to drastically effect the run time as our values increase.
207+
Overall, our results suggest that for computing Fibonacci numbers, the iterative method is the best choice for
208+
run time efficiency, while memoization provides a viable compromise when a recursive approach is necessary.
209+
210+
Importantly, our results are ran and averaged across a variety of operating systems, including Windows, and Mac,
211+
in order to provide the most inclusive and well-rounded analysis possible.
150212

151213
# Next Steps
152214

@@ -165,4 +227,4 @@ These references were utilized during the creation of the experimental harness u
165227
* <https://github.com/Allegheny-Computer-Science-202-S2025/computer-science-202-algorithm-engineering-project-2-krishatcher>
166228
* timing and output logic in this repo influenced by AEP 2
167229
* <https://stackoverflow.com/questions/2819625/how-to-use-a-callable-as-the-setup-with-timeit-timer>
168-
* successfully using the `timeit` library
230+
* successfully using the `timeit` library

0 commit comments

Comments
 (0)