Stacks:
| Name | Description |
|---|---|
| push | Adds a new entry to the top of the stack |
| pop | Removes and returns the stack’s top entry |
| peek | Retrieves the stack’s top entry without changing the stack |
| isEmpty | Returns whether the stack is empty |
| clear | Removes all entries from the stack |
Remember: You can only interact with the item at the top of the stack!
- Don’t implement extra features that go against the specification!
- This means no
toArray!
public interface StackInterface<T> {
void push(T newEntry);
T pop();
T peek();
boolean isEmpty();
void clear();
}Case: Stack is empty, what to do with pop and peak?
nullSecurity Note:
Relevancy: “The most important ADT in computer science”
- We wouldn’t have methods or recursion without stacks!
- In this introduction we’ll be using the stack to manipulate algebra.
- The techniques are universal, and used everywhere.
Algebraic Notation:
Note: Why Prefix and Postfix Matter
- In infix, precedence can be ambiguous, which is why parenthesis and the precedence (order of operations) exists.
- So for a computer to evaluate an infix expression, it needs two stacks (variable and operator stack) and it needs to evaluate order of operations.
- In prefix and postfix, precedence is not ambiguous, no parenthesis are needed.
- So prefix and postfix is easier and faster to execute on a computer (you only need to use one stack to evaluate, and you don’t need to worry about order of operations).
# Infix
a + b
# Prefix
+ a b
# Postfix
a b +# Infix
a + b / c
# Prefix
+ a / b c
# Postfix
a b c / +Warning: Keep terms on their original sides when converting expressions
- Using the associative rule to switch sides will lose points.
Balanced Expression: An expression with matching brackets and parenthesis.
Q: How do you tell if an infix expression is balanced?
A: Read the expression character-by-character, and:
[, {) to the stack as you read it], }) from the stack as you read itQ: How do you programmatically convert an infix expression \to postfix?
A: Read the expression character-by-character and use a stack to store operators:
a, b) get appended to the postfix expression as we read them.-, +) get pushed into the operator stack as we read them.Remember: The parenthesis themselves don’t get added into postfix notation.
| Current Character | Postfix Form | Operator Stack |
|---|---|---|
| a | a | |
| + | a | + |
| b | ab | + |
| * | ab | +* |
| c | abc | +* |
| abc* | + | |
| abc*+ |
| Current Character | Postfix Form | Operator Stack |
|---|---|---|
| a | a | |
| - | a | - |
| b | ab | - |
| + | ab- | + |
| c | ab-c | + |
| ab-c+ |
| Current Character | Postfix Form | Operator Stack |
|---|---|---|
| a | a | |
| ^ | a | ^ |
| b | ab | ^ |
| ^ | ab | ^^ |
| c | abc | ^^ |
| abc ^ | ^ | |
| abc ^^ |
^ may appear to have the same precedence as the first ^—because they’re both the same symbol (so you may want to do ab^c^)—but the second ^ has a higher precedence because it’s nested in the first one!| Current Character | Postfix Form | Operator Stack |
|---|---|---|
| a | a | |
| / | a | / |
| b | ab | / |
| * | ab/ | * |
| ( | ab/ | *( |
| c | ab/c | *( |
| + | ab/c | *(+ |
| ( | ab/c | *(+( |
| d | ab/cd | *(+( |
| - | ab/cd | *(+(- |
| e | ab/cde | *(+(- |
| ) | ab/cde- | *(+( |
| ) | ab/cde-+ | *( |
| ) | ab/cde-+* |
Note: When implementing this in code, make sure that the expression is balanced, or throw an exception when something illegal happens.
Q: How do you programmatically evaluate a postfix expression?
A: We’ll use a stack to evaluate it.
s.push(t))op = t)rhs = s.pop())lhs = s.pop())s.push(lhs op rhs))s.pop()Stacks make method calling and recursion possible.
public static void main(string[] args) {
int x = 5;
int y = methodA(x);
}
public static int methodA(int a) {
a = methodB(a);
return a;
}
public static int methodB(int b) {
return b;
}So, by the time methodB() begins execution, the program activation record looks like this:
methodBmethodAmainFound in java.util
Methods:
T push(T item);
T pop();
T peek();
boolean empty();Implementing a stack with a singly linked list is trivial.
head node as the top of the stack.public final class LinkedStack<T> implements StackInterface {
private Node head;
? /* constructor goes here */
public T peek() {
if (isEmpty()) {
throw new EmptyStackException();
}
return head.data;
}
public T pop() {
T top = peek();
head = head.next;
return top;
}
public T push(T entry) {
Node newEntry = Node(entry);
if (head != null) {
newEntry.next = head;
}
head = newEntry;
}
/* private Node inner-class here */
}Implementing a stack with an array is best done by using the end of the array as the top of the stack, as it’s the easiest to access.
Vector: Object that behaves like a high-level array.