|
Comp210: Principles of Computing and Programming
|
First, let's return to an in-class example, reversing a list.
|
Sample solutions. |
As in this example, different algorithms can lead to fundamentally faster ways of doing a task. We'll talk more about this later. Always keep in mind that it's more important to write a function so that it is clear, correct, and maintainable, than one that is faster but more confusing. Studies show that even experienced professional programmers aren't good at predicting where bottlenecks occur in code. First write your code correctly; if you find it runs too slowly, you can use DrScheme's profiler and find out which functions you want to focus on, to optimize later.
Let's contrast those two examples to the following.
|
Neither approach is always better. As with summing the elements in a list, for some problems, it doesn't really matter much. On the other hand, as in the above problems, often the choice matters significantly. One of the approaches might be significantly easier and more efficient.
It turns out that we can do everything without an accumulator that we can with one, and vice versa, the difference can be surprisingly awkward. For example, consider taking a list of numbers representing bank deposits andwithdrawls, and asking if the balance ever goes negative. Our input might be (list +100 -21.50 -41.50 +200). Unfortunately, looking at just the rest of this list doesn't help you build the answer to the full problem; it really depends on the running balance-so-far.
However, as the hand-evaluations show, accumulator-style functions yield tail-recursive functions -- the answer to the recursive call is the answer to the entire question. This means that you don't build up a whole waiting list of pending function calls. This is also known as a loop -- looping is just a special case of recursion.
On the other hand, with accumulator-style functions, you must decide what is the accumulator accumulating? So far, we've often answered this step for you, but it is generally the hardest part of using accumulators. Sometimes, answering this question can be very difficult.
Reverse- and forward-accumulation are not mutually exclusive. The two ideas can be combined, as you've seen in a couple in-class examples. The following is also an example of this.
We've had a bunch of examples of summing things. Here's another variant that is very useful, not only pedagogically, but also for real applications.
Develop a function (prefix-sums (list 1 8 7 3)) returns (list 1 9 16 19) (prefix-sums (list 1 1 1 1)) returns (list 1 2 3 4) |
Sample solution. |
If you have time, here's a problem somewhat similar to the previous one that you may be familiar with already, Pascal's Triangle. (For lots of neat info on why it's interesting, see here or here.) As it is usually drawn, Pascal's Triangle looks like this:
1
1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 ...
|
Last Revised Tuesday, 24-Aug-2004 13:49:08 CDT
©2004 Stephen Wong and Dung Nguyen