The Program Life Cycle.

Download Report

Transcript The Program Life Cycle.

Day 8: Stacks 2.
1. Admin.
2. Review.
3. The application level.
1. Admin.
1) Take in program 3.
2)
Today: stack applications.
Thursday: review for Test 1
Next Tuesday: Test 1.
2.
Review.
Stacks.
A. The Abstract Level.
Stacks are time-ordered, LIFO data structures
with one access point, the top, Pop and
Push as access mechanisms, and Empty
and Full as observers.
Review.
B. The Implementation level.
The simplest way to implement a stack is
using an array as the container, and a
separate integer, Top, that stores the index
of the element on the top of the stack.
Review.
C. The Application level.
Stacks, in effect, remember things in reverse
order.
This can be useful: (1) any time you need to
back-track / retrace your steps; (2) if you
need to compare something in normal and
reverse order; (3) if you need to reverse
the order of operations.
3.
The Application level.
Specific examples:
1. Finding your way back out of a tree
structure, using a stack containing the
addresses of the nodes you traversed.
See diagram.
Palindromes.
2. Testing for palindromes e.g.
A
MOM
RADAR
WASITARATISAW
ABLEWASIEREISAWELBA
AMANAPLANACANALPANAMA
Pseudocode.
How could we use stacks to determine if a string
is a palindrome?
Why is “RADAR” a palindrome, but “TWIT” is not?
Exercise: Devise a pseudocode algorithm.
Subprogram calls.
3. Subprogram calls.
When one method calls another (which may
in turn call another…) what problem
needs to be solved?
How would stacks work?
See diagram.
Base Conversion.
4. Base Conversion (mentioned last time).
For example, suppose you want to convert
from base 10 to base 4. What is the
algorithm by hand?
1) Repeatedly divide by the base (4);
2) Read remainders from bottom to top.
Problems.
How could we use a stack to:
(a)convert 87 base 10 to base 4;
(b) convert 156 base 10 to base 16.
Infix to Postfix.
5. EVALUATING POSTFIX.
When your program is compiled the compiler
first changes all your arithmetic
expressions from “infix” to “postfix”
notation.
What does this mean?
Infix.
Normally, we think in “infix”: we put the
operator in between the operands.
Operands include literals like 3 and 4.5 and
also variable names (Num) and numeric
function calls e.g. Sum (Num)
E.g. of infix: “5 * 3” “Num + 7”
Or “Yoda likes Luke”
Why postfix?
Infix can be ambiguous
E.g. 3 + 5 * 7 could mean….
True, it is not ambiguous if we use the rules of
precedence, but then there are 2 problems:
(1) The rules of precedence have to be
translated into binary and implemented (is
this really necessary?), and….
Ease of evaluation.
(2) At run-time, the arithmetic expression can no
longer be evaluated in a single pass going from
left to right.
e.g. when passing through
3 + 5 * 7, when it reaches the + it cannot tell
whether it should do it, or wait (it should wait,
because the * has higher precedence).
Ease of evaluation.
Likewise, even if something seems to have highest
priority, maybe it doesn’t, because of the use of
parentheses, e.g. in
3 * (5 + 8)
To avoid both problems, it would be nice if we had
an unambiguous format, where expressions can
be evaluated in a single pass and operations will
be performed in the right order.
Infix to Postfix.
That is the idea of postfix, or “reverse
Polish notation,” where the operators are
placed after the operands.
Infix
Postfix
3*5
35*
“Yoda likes Luke” “Yoda Luke likes”
Infix to Postfix.
Infix
3+5*6
7 * (3 + 5)
(9 – (2 + 3)) * 7
Postfix
3 56*+
??
??
Advantage of postfix.
The idea is to avoid having to translate rules
of precedence into binary and having to do
multiple passes of the same expression,
making the machine code more compact
and faster to execute.
Note also that no parentheses are required in
postfix. Why not?
Translating infix to postfix.
Idea: use 2 parallel stacks.
One stack will be used to store operators, the
other, parallel stack will hold their
associated precedence level (a number).
Recall that C# has very simple precedence
rules:
Precedence in C#.
1) *, / have the highest precedence;
+, - have lower precedence;
2) If 2 operators have equal precedence,
evaluate left to right;
3) Rules 1 and 2 can be overridden by the use
of parentheses.
Handling Precedence.
To implement this, we assign * and / a
precedence of 2, and + and – a precedence
of 1. We will also allow precedence to be
promoted by parentheses, using a variable
PrecedenceProm.
If we encounter a left parenthesis, we add 3
to PrecedenceProm; if we encounter a
right parenthesis….
A worked example.
How does it all fit together?
Consider how we get from the infix input:
a * (b+c) – d
to the postfix output:
abc+*d–
See the handout, work through.
Evaluating postfix expressions.
Once an expression is converted to postfix, it
can also be evaluated using a stack.
This time, only a single stack (of operands) is
required.
There is an elegant algorithm that requires
only one pass through the postfix
expression.
Evaluating postfix algorithm.
1. Initialize Stack.
a. Clear Stack [can be done by constructor]
This could be as simple as Top = -1
b. Extract first token [Each operand or
operator is a token]
This is a priming read.
Evaluating postfix algorithm (cont.).
2. Process Stack.
while more tokens {
1. if token is an operator {
pop, pop, do op
push result }
else push operand on stack;
2. Get next token } // end while
Evaluating postfix algorithm (cont.).
3. Finalize Stack.
// At the end, the final answer will have
// been pushed on the stack, so
1. Pop and display final answer.
E.g.s to try:
9 6 +3*
2 6 *4 - 2 /