CSE 220 Week 5
CSE 220 Week 5
Mushtari Sadia
Stack
Introduction
Basic Operations
● Push(obj): adds obj to the top of the stack ("overflow" error if the stack has fixed capacity,
and is full)
● Pop: removes and returns the item from the top of the stack ("underflow" error if the stack
is empty)
● Peek: returns the item that is on the top of the stack, but does not remove it ("underflow"
error if the stack is empty)
Stack
Fixed capacity - implemented with array Unlimited capacity - implemented with linked list
Fixed Capacity Stack Example
Stack of
Size 4
Push(1)
1
Push(2)
1
Push(3)
1
Push(4)
4
1
Push(5) Stack Overflow Error!
1
Peek
4
1
Pop
4
1
Pop
1
Pop
1
Pop
1
Pop Stack Underflow Error!
import numpy as np
class Stack:
def __init__(self):
self.stack = np.zeros(4, dtype=int) Code
Implementing The
self.top = -1
Push(1) top = 0
stack.push(1)
Code running
behind the scene:
Push(2) top = 1
stack.push(2)
Code running
behind the scene:
Push(3) top = 2
stack.push(3)
Code running
behind the scene:
3
Push(4) top = 3
stack.push(4)
4
Code running
behind the scene:
3
Push(5) top = 3
stack.push(5)
4
Stack Overflow Error!
Code running
behind the scene:
3
4 print(stack.peek())
4 3 Code running
behind the scene:
def peek(self):
Will return 4, but
2 if self.top == -1:
print(stack.pop())
4 3 Code running
behind the scene:
def pop(self):
stack.pop()
Code running
behind the scene:
def pop(self):
Will remove 3
2 if self.top == -1:
print("Stack underflow")
from the stack else:
item = self.stack[self.top]
1 self.stack[self.top] = None
self.top -= 1
return item
Pop top = 0 Driver code:
stack.pop()
Code running
behind the scene:
def pop(self):
stack.pop()
Code running
behind the scene:
def pop(self):
stack.pop()
Stack Underflow
Error! Code running
behind the scene:
def pop(self):
if self.top == -1:
print("Stack underflow")
else:
item = self.stack[self.top]
self.stack[self.top] = None
self.top -= 1
return item
Linked List Based Implementation
Stack Creation
Push
Pop
Peek
Stack Applications
1. Call Stacks
def main:
A()
def A:
B()
def B:
print("hello world")
main()
Stack Applications Hello
2. Reverse a word
def reverse_word(word):
word = "Hello"
stack = Stack()
reversed_word = reverse_word(word)
print(reversed_word)
# Push each character of the word onto the stack
for char in word:
stack.push(char)
reversed_word = ""
# Pop each character from the stack to get the reversed word olleH
while not stack.is_empty():
reversed_word += stack.pop()
return reversed_word
Stack Applications
3. Undo
6. Parenthesis Matching
Postfix Expression Evaluation
● This is an expression:
Expression Tree
Prefix Traversal pre
x
Prefix Traversal pre
x +52
Prefix Traversal pre
x +52 -31
Prefix Traversal pre
x +52 -31
Ans: x + 5 2 - 3 1
Infix Traversal in
5+2
Infix Traversal in
5+2 x
Infix Traversal in
5+2 x 3-1
Same as this:
Postfix Traversal post
52+ 31- x
Ans:
Postfix Expression Evaluation
# your code
Output: 14
If character is an operand ( 5 / 2 / 3 )
Push to stack
If character is an operator ( + * / - )
Pop last two characters from stack
Perform operation on last two characters
Push answer to stack
Postfix Expression Evaluation
Possible solution:
5
Postfix Expression Evaluation
Possible solution:
5
Postfix Expression Evaluation
Possible solution:
5 + 2 = 7
Postfix Expression Evaluation
Possible solution:
7 5 + 2 = 7
Postfix Expression Evaluation
Possible solution:
7 x 2 = 14
Postfix Expression Evaluation
Possible solution:
14 7 x 2 = 14
Postfix Expression Evaluation
Possible solution:
14
Postfix Expression Evaluation - Another Example
Parenthesis Matching
Input: exp = “[()]{}{[()()]()}”
Output: Balanced
6. Parenthesis Matching
Stack ->
Queue-> First In First Out
Enqueue(1)
Push(2) stack
queue
1 2
Enqueue(2)
Push(3) stack
queue
1 2 3
Enqueue(3)
Push(4) stack
queue
4 1 2 3 4
Enqueue(4)
Peek stack
queue
4 1 2 3 4
4
3
Will return 4, 1
2
but will not
remove 4 from Will return 1,
the stack but will not
1
remove 1 from
the queue Peek
Pop stack
queue
4 2 3 4
3
1
Dequeue
Pop stack
queue
3 4
Dequeue
Pop stack
queue
2
3
Dequeue
Pop stack
queue
Dequeue
Queue
A queue has three main operations (like a stack). These operations are:
1. Enqueue: It stores a new object in the queue at the end. If the queue is full, this
operation throws a QueueOverflow exception.
2. Dequeue: It removes the first object from the queue. If the queue is empty, this
operation throws a QueueUnderflow exception.
3. Peek: This operation shows the first item in the queue. This operation does not
remove any items from the queue. If the queue is empty, this operation throws a
QueueUnderflow exception.
Queue def dequeue(self):
if self.size == 0:
class Queue:
print("Queue is empty")
def __init__(self, max_size):
return None
self.max_size = max_size
item = self.queue[self.front]
self.queue = [None] * max_size
self.queue[self.front] = None
self.front = 0
self.front = (self.front + 1) % self.max_size
self.rear = -1
self.size -= 1
self.size = 0
return item
1%4 = 1
2%4 = 2
3%4 = 3
4%4 = 0
5%4 = 1
6%4 = 2
Queue() #when __init__ is called
size = 0 max_size=4
front=0
1 2
1 2 3
1 2 3 4
size = 4 max_size=4
front=0
1 2 3 4
1 2 3 4
def peek(self):
rear=3 if self.size == 0:
print("Queue is empty")
return None
Will return 1 but will not
return self.queue[self.front]
1 remove it
Dequeue
size = 3 max_size=4
front=1
def dequeue(self):
if self.size == 0:
2 3 4
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
Will return 1 and remove it self.size -= 1
1 return item
Dequeue
size = 2 max_size=4
front=2
def dequeue(self):
if self.size == 0:
3 4
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
self.size -= 1
2 return item
Dequeue
size = 1 max_size=4
front=3
def dequeue(self):
if self.size == 0:
4
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
self.size -= 1
3 return item
What will happen if I dequeue now?
Dequeue Think!
size = 1 max_size=4
front=3
def dequeue(self):
if self.size == 0:
4
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
self.size -= 1
3 return item
front % max_size = 4%4 = 0
Dequeue
size = 0 max_size=4
front=0
def dequeue(self):
if self.size == 0:
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
self.size -= 1
4 return item
Dequeue Queue Underflow Error!
size = 0 max_size=4
front=0
def dequeue(self):
if self.size == 0:
print("Queue is empty")
return None
item = self.queue[self.front]
rear=3 self.queue[self.front] = None
self.front = (self.front + 1) %
self.max_size
self.size -= 1
return item
size = 0 max_size=4
front=0
rear=3
Enqueue(1)
size = 1 max_size=4
front=0
enq(a)
a
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
()
deq
b
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
()
deq
(b)
peek()
b b
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
()
deq
(b)
peek() enq(c)
b b bc
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
()
deq
(b)
peek() enq(c)
b b bc
peek()
(c)
bc
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
enq(a) enq(b)
a ab
()
deq
(b)
peek() enq(c)
b b bc
peek()
(c)
deq()
bc c
In exam, write your answer like this
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
Simulations
Type 2
You need to perform the following operations on a array based queue where
the length of array is 4 and starting index of front and back is 3.
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue.
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a)
enq(b)
deq()
peek()
enq(c)
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0
enq(b)
deq()
peek()
enq(c)
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0
enq(b) b N N a 1
deq()
peek()
enq(c)
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0 0
enq(b) b N N a 1
deq() b N N N
peek()
enq(c)
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0 0
enq(b) b N N a 1
deq() b N N N
peek() b N N N
enq(c)
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0 0
enq(b) b N N a 1
deq() b N N N 2
peek() b N N N
enq(c) b c N N
peek()
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0 0
enq(b) b N N a 1
deq() b N N N 2
peek() b N N N
enq(c) b c N N
peek() b c N N
deq()
(N=None)
enqueue a, enqueue b, dequeue, peek, enqueue c, peek, dequeue
0 1 2 3 front rear
N N N N 3 3
enq(a) N N N a 0 0
enq(b) b N N a 1 1
deq() b N N N 2
peek() b N N N
enq(c) b c N N
peek() b c N N
deq() N c N N
(N=None)
In exam, write your answer like this
A Discussion on the Importance of Stacks and Queues
By now you well understand that larger complex data structures are made of
smaller building block data structures. For example, multi-dimensional and
circular arrays or vectors are made using linear arrays; lists are used to create
sets and maps (which is called a dictionary in some languages and associated
arrays in some other). However, as building block data structures, stacks and
queues are unique in some sense.
A Discussion on the Importance of Stacks and Queues
For example, a set or a map that you create from a linked list provides
additional features over their building block component that is the list.
However, stacks and queues are strictly restricted forms of linked list (in rare
cases, where you know the maximum number of elements you will put in
them, you can use arrays for stacks and queues also). In other words, they do
not provide any new features that a linked list does not already have. So it is a
natural question why stacks and queues are considered fundamental data
structures.
A Discussion on the Importance of Stacks and Queues
One reason for their importance is that scenarios where you need a linked list
behave like a stack or queue is very frequent. For example, you need stacks
for language parsing, expression evaluation, function calls, efficient graph
traversals, etc. Queues are similarly important for resource scheduling, time
sharing of CPU among candidate processes, message routing in network
switches and routers, and efficient graph traversal.
A Discussion on the Importance of Stacks and Queues
Another central reason is that you often do not want to give access to the underlying list data
structure that forms a stack or queue to the code that requested an insert or a removal from the
stack/queue. If access to the list is provided then the code becomes more insecure. To consider this
case, imagine direct access to the function call stack is possible. Then a program can manipulates the
stack and jump from the current function to a much earlier function, instead of the immediate
predecessor function that called it. Why this might be a problem? Well, this would not be a problem if
all the functions in the stack belong to your own program. However, in real-world, library functions,
operating system’s service functions interleave with user program’s functions in the stack.
Unprotected jumps to those functions can crash the system.
A Discussion on the Importance of Stacks and Queues
A third reason to have stack and queues as restricted form of linked lists (or
arrays) is that their restricted functions provide smaller code that can fit in
very short memory or can even be implemented inside hardware devices
directly. This feature is particularly important when you need fast response,
for example, in routers and switches. In fact, array based stack and queue
implementations are most suited in cases like this.