Tues, Mar. 21
Hand out practice midterm, note on Matcher to replace StringTokenizer for pa03 (too late of course for actual pa03 work)
Queues—pg. 227, a “pure” Queue. Put elements in one end and never get to access them until they come out the other end.
This is known as FIFO.
Operations: enqueue, dequue, getFront--see problem on Practice exam.
Again no size() or iterator, and we can only access the “front” element directly.
Queues are use for dataflow and “workflow”, where tasks flow from one person to another. In cases like this, different programs or different parts of the same program are doing the enqueue and dequeue operations. The queue can save objects that are in transit and allow pacing flexibility at both ends.
For a little app, consider the following scenario. Suppose your program occasionally exhibits bad behavior that becomes apparent at the end of its work. So you need a log of its activities to help you debug this problem. But you don’t want a log of all the successful runs. What to do?
Answer: Queue up the log messages and dump them out only in the troublesome case at the end of the run.
Usage of this service:
Log myLog = new Log()Of course, dumpLog() empties the log information, so it can’t be done twice usefully. That’s why I called it dumpLog instead of printLog, which should be repeatable. We could implement printLog by re-enqueuing the Strings, after enqueuing a marker, or enqueuing on a differenct queue and switching queues.
Priority Queues
We're not officially covering this now, but just FYI
Priority queues are queues only in a sense. Real queues are FIFO, but priority queues are highest-priority-out, whenever it came in.
Classic operation names: insert, deleteMin. findMin--see picture on pg. 241.
Recursion: Chap. 7, we’ll cover up to pg. 266, inclusively, after the midterm. Read 7.2 for next time. Sec. 7.5 and 7.6 are covered in cs310.
We consider the idea of recursive dictionary lookup as described on pg. 252. We could imagine placing post-its on words we are studying, so we can get back to the original word we looked up. These post-its can be thought to represent a stack of our recursive search for meaning of words. They help us back up to where we were before.
Another aspect of recursion is also seen in such dictionary searches. If word A is defined in terms of word B, and B in terms of C, and C in terms of A, we could end up in an endless cycle if we blindly followed the algorithm. Similarly, we need to watch out for this when using recursion in programming.
First code example: Fig. 7.1.
Looking for sum up to n: 1 + 2 + 3 +… + (n-1) + n,
<--see sum to n-1 ->
So we can say: sum(n) = sum(n-1) + n, a recursive formula. Also needs a base case: sum(1) = 1 to get started.
We can build a function based on this idea, as shown in Fig. 7.1. We called the function sum instead of s.
The computation for n=1 is the “base case”, while the computation for n>1 is the recursive case, where case n is expressed in terms of case n-1, making progress towards the base case.
Where’s the stack here?
Answer: we’re using the program execution stack, which has been quietly helping us call functions all along.
Each local variable in a function is housed on the program stack, and when a call is made, the language system starts using a new part of the stack for that newly called function, in effect pushing the old local variables onto the stack. They are held there, untouched, until execution returns to the original function environment.
Objects themselves are not on the stack, but references to them can be, and often are.
When we display a trace for recursion, we indent for each recursive level, like this:
top level calls sum(4)