## Announcements

• since there’s been a delay getting project 2 to you, I’ve moved its due date to the 17th
• we’ll be talking about the stuff you’ll be doing for project 2 in class today
• no quiz today so I can catch up
• if you have questions about the quiz answers (which I sent out earlier today) we can talk about them at the break
• last, let’s go over amortized analysis since I kinda messed up the explanation last time
• THANKS, BILLY G
• (the lecture notes from last time have been updated)

## Precedence and associativity

• Operator precedence is “PEMDAS”, basically
1. Parentheses come first, and have the highest precedence.
2. Exponentiation is next.
3. Multiplication and division have the same precedence.
4. Addition and subtraction have the same precedence as well, and are the lowest.
• Precedence tells you where “virtual parentheses” go.
• In 3 + 9 * 4^3
• Exponentiation has the highest precedence, so (4^3) is evaluated first.
• Then comes multiplication, so (9 * (4^3)) is next.
• Finally addition, so the overall expression is the same as (3 + (9 * (4^3))).
• Operator associativity is the direction we evaluate when we have multiple operators of the same precedence in a row.
• In 3 - 4 + 5, we don’t do addition first. + and - have the same precedence.
• So, we go left-to-right. We say addition and subtraction are left-associative (or “left-to-right” if that makes it easier to remember).
• and / are the same.
• But exponentiation, ^, is right-associative. 3^4^5 is interpreted as 3^(4^5).
• To summarize, here is a table of these operators’ precedence and associativity.

Operator Precedence Associativity
( ) 1st left(-to-right)
^ 2nd right(-to-left)
* / 3rd left(-to-right)
+ - 4th left(-to-right)

In the above table, the precedence is listed as 1st, 2nd etc. However when implementing this algorithm, we might represent the precedence as integers where the highest (1st) precedence is the largest integer. This can cause confusion, so I would recommend abstracting this into a separate function, like isHigherPrecedence(a, b) which should say that e.g. * has a higher precedence than + but lower than ^.

## Infix to Postfix

• Last time we talked about RPN (postfix expressions)
• These are very easy to evaluate with an algorithm.
• But we humans are used to writing infix expressions, where the operators come between the operands
• It’s possible to evaluate infix expressions, but it’s more complicated.
• It would be nice if we could turn a human-friendly infix expression into a computer-friendly postfix expression…
• If we have a table of operator precedences and associativities, an algorithm becomes possible.
• This algorithm takes a sequence of tokens in, and produces the output string.
• A token is sort of the equivalent of a “word” or “punctuation mark”
• So 3, 23590, +, *, number_of_people are all tokens
• We will need a stack to hold operators.
• We will also need an output string to hold the postfix expression being built.
• So here we go.
1. For each token in the input:
• If it is an operand (number, variable), append it to the output string.
• If it is an open bracket, push it onto the stack.
• If it is an operator:
• While the stack is not empty:
• If the top of the stack is an operator of greater or equal precedence:
• Pop that operator from the stack and append it to the output string.

A consequence of this is that: you can never have two operators of the same precedence next to each other on the stack.

• If the top of the stack is an open bracket:
• Break out of the loop.
• Push the new operator onto the stack.
• If it is a close bracket:
• While the stack is not empty:
• If the top of the stack is a non-bracket:
• Pop it and append it to the output string.
• If the top of the stack is the matching open bracket:
• Pop it from the stack and break out of the loop.
2. After all input tokens have been read:
• While the stack is not empty:
• Pop the operator from the stack and append it to the output string.
• Let’s do an example (with only left-associative operators for now…):
• 3 + 4 * x + y - 9 / z
• According to PEMDAS, this is interpreted as ((3 + (4 * x)) + y) - (9 / z)
• The stack and output string will look like this after each token:

I messed up this example originally. This is the correct sequence of steps and output.

3   3
+ + 3
4 + 3 4
* +* 3 4 * > +
x +* 3 4 x
+ + 3 4 x * + pop * and +, push +
y + 3 4 x * + y
- - 3 4 x * + y + - == + so pop +
9 - 3 4 x * + y + 9
/ -/ 3 4 x * + y + 9 / > -
z -/ 3 4 x * + y + 9 z
(end) - 3 4 x * + y + 9 z / start popping
3 4 x * + y + 9 z / -

You can download and play this powerpoint to watch/hear me explain how this works.

Also, even though we do some of the additions before the division, the expression is still correctly evaluated. It is possible to intermix operations like this as long as the end result is the same.

• Let’s evaluate that using the algorithm we learned last time
• We could, in fact, chain these two algorithms end-to-end
• Every time we would append an operand, instead push it onto the operand stack
• Every time we would append an operator, instead evaluate it with the top two operand stack items
• Hey, this is project 2!
• Of course, we can modify this algorithm to handle error cases as well:
• Mismatched or unmatched parentheses
• Missing operands

## Recursion

• What is recursion?
• Recursion is a way of solving problems by breaking them up into smaller subproblems.
• In many cases, you do the same small step over and over until a condition is met.
• Does that sound familiar?
• Recursion is really a different way of writing a loop.
• So don’t get too scared by the concept and notation.
• A loop is what we call iterative - explicitly saying that something repeats.
• The basic idea
• Let’s say we want to sum all the values in an array.
• Let’s take an array that looks like {5, 9, 4, 22, 13, 7, 10}
• How would you write that as a loop?
• sum = 0; for(each item in the array) sum += item;
• Let’s look at it a different way.
• If you have an array that looks like this: {5, ...}
• where ... means “the rest of the array”
• What is the sum?
• 5 + (the sum of the rest of the array).
• This is really kinda more like how your computer sees the problem.
• Your computer doesn’t “see” the whole array at once, just one item at a time.
• So at any given point, it is only focusing on that first item in the array.
• The rest of the items of the array are… another array.
• So the sum of ... is the sum of {9, ...}
• And we can keep going.
• Eventually, we get to this case: {10}.
• There is no “rest of the array.”
• So, the sum is just 10.
• We could think of this whole process as doing 5+(9+(4+(22+(13+(7+(10))))))
• The terminology
• A recursive case is when the problem is solved by solving a subproblem, and then doing a step.
• A base case is when the problem is easily solved without any subproblems.
• Termination is important: it means that recursive cases must eventually lead to a base case.
• If you cannot guarantee or prove that, you can end up with infinite recursion.
• Basically, an infinite loop.
• By analogy to a loop…
• The base case is the loop condition. When the condition is no longer satisfied, the loop is over.
• The recursive case is the loop body. It’s what you do while the condition is satisfied.
• Termination means being able to prove that the condition will eventually become false (or that you will break from the loop).
• If we have a for loop:

  for(int i = 10; i > 0; i--) {
stuff();
}

• The base case is when i == 0.
• The recursive case is the stuff() inside the loop.
• Termination is guaranteed by i-- - i will decrease by 1 each time, and will eventually become 0.
• Forgetting this increment would give us an infinite loop!
• A practical example
• Exponentiation is repeated multiplication.
• B^n is n copies of B multiplied together.
• How would we write this iteratively?
• product = 1; for(i = n; i > 0; i--) product *= B;
• What is the base case? (When does the loop stop?)
• When n == 0. What is anything raised to the 0 power?
• 1.
• So we’d write 1, if n == 0.
• What is the recursive case?
• When n > 0.
• In that case, we have something like B * ..., where ... represents how many Bs?
• n - 1.
• So, we’d write B * B^(n - 1), if n > 0.
• Are we guaranteed to terminate?
• Yes – in the recursive cases, we always make n smaller, and eventually we get to 0.
• Written in mathematical notation:

        ⎧ B * B^(n - 1), if n > 0
B^n = ⎨ 1            , if n == 0
⎩

• Written in Java… (see Ex15RecursivePower.java)

## A non-terminating example

• Let’s write a recursive function to search a linked list for a value
• There are two base cases: one successful, and one unsuccessful.
• Success happens when node.value == searchedValue.
• Failure happens when node == null (i.e. we got to the end of the list).
• What is the recursive case?
• node != null && node.value != searchedValue
• In which case, what do we do?
• return search(node.next, searchedValue)
• Written in Java… (see Ex16LinkedSearch.java)
• There is no guaranteed termination
• It is possible to have a “ring” of nodes
• To be fair, neither the iterative nor recursive searches would work.