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
!
Example: Stack interface
public interface StackInterface<T> { void push(T newEntry); pop(); T peek(); T boolean isEmpty(); void clear(); }
Case: Stack is empty, what to do with pop
and peak
?
null
Security 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).
Example: The same expression in infix, prefix, and postfix
# Infix a + b # Prefix + a b # Postfix a b +
Example: The same expression in infix, prefix, and postfix
# 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.
Example: Converting infix \to postfix with a stack
- Infix Expression: a+b*c
Current Character Postfix Form Operator Stack a a + a + b ab + * ab +* c abc +* abc* + abc*+
- Thus, the postfix form of a+b*c is abc*+
- Infix Expression: a - b + c
Current Character Postfix Form Operator Stack a a - a - b ab - + ab- + c ab-c + ab-c+
- Thus, the postfix form of a-b+c is ab-c+
- Infix Expression: a ^ b ^ c
Current Character Postfix Form Operator Stack a a ^ a ^ b ab ^ ^ ab ^^ c abc ^^ abc ^ ^ abc ^^
- Thus, the postfix form of a ^ b ^ c is abc ^^
- Important: The second
^
may appear to have the same precedence as the first^
—because they’re both the same symbol (so you may want to doab^c^
)—but the second^
has a higher precedence because it’s nested in the first one!
- Infix Expression: a / b * ( c + (d-e))
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-+*
- Thus, the postfix form of a / b * ( c + (d-e)) is 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.
Example: Program activation records
public static void main(string[] args) { int x = 5; int y = methodA(x); } public static int methodA(int a) { = methodB(a); 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:
methodB
methodA
main
- (This demonstrates LIFO, the last method in is the first one executed.)
Found in java.util
Methods:
push(T item);
T pop();
T peek();
T boolean empty();
Implementing a stack with a singly linked list is trivial.
head
node as the top of the stack.Example: Implementing basic stack methods with SLI
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.