Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Stacks and Queues

Download as pdf or txt
Download as pdf or txt
You are on page 1of 70

CS1006T Data Structures

Stacks and Queues

Chandrabose Aravindan
<AravindanC@ssn.edu.in>

Professor of Information Technology


SSN College of Engineering

April 09, 2024

C. Aravindan (SNU) Data Structures April 09, 2024 1 / 36


Stack ADT

As the name suggests, Stack is a linear collection where objects are


“stacked” one above the other
Insertion and deletion can only happen at the “top”
It is a special kind of a list where insertion and deletion happen at one
end only
There is only one recognized position called “top”
It is also referred to as Last-in-First-out (LIFO) structure

C. Aravindan (SNU) Data Structures April 09, 2024 2 / 36


Stack Operations

stk = Stack() — creates and returns a new Stack structure


stk.isEmpty() — returns “TRUE” if stk is empty and returns
“FALSE” otherwise
stk.clear() — removes all the objects in stk and resets it to an empty
stack

C. Aravindan (SNU) Data Structures April 09, 2024 3 / 36


Core Stack Operations

stk.push(x) — inserts object x at the top of the stack


⟨⟩ —> ⟨x ⟩
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨x , en , en−1 , · · · , e2 , e1 ⟩

C. Aravindan (SNU) Data Structures April 09, 2024 4 / 36


Core Stack Operations

stk.push(x) — inserts object x at the top of the stack


⟨⟩ —> ⟨x ⟩
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨x , en , en−1 , · · · , e2 , e1 ⟩
stk.top() — returns the object at the top of the stack stk (stk is not
modified!)
⟨en , en−1 , · · · , e2 , e1 ⟩ —> en
⟨⟩ —> ???

C. Aravindan (SNU) Data Structures April 09, 2024 4 / 36


Core Stack Operations

stk.push(x) — inserts object x at the top of the stack


⟨⟩ —> ⟨x ⟩
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨x , en , en−1 , · · · , e2 , e1 ⟩
stk.top() — returns the object at the top of the stack stk (stk is not
modified!)
⟨en , en−1 , · · · , e2 , e1 ⟩ —> en
⟨⟩ —> ???
stk.pop() — removes the object at the top of the stack stk
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨en−1 , en−2 , · · · , e2 , e1 ⟩
⟨x ⟩ —> ⟨⟩
⟨⟩ —> ???

C. Aravindan (SNU) Data Structures April 09, 2024 4 / 36


Core Stack Operations

stk.push(x) — inserts object x at the top of the stack


⟨⟩ —> ⟨x ⟩
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨x , en , en−1 , · · · , e2 , e1 ⟩
stk.top() — returns the object at the top of the stack stk (stk is not
modified!)
⟨en , en−1 , · · · , e2 , e1 ⟩ —> en
⟨⟩ —> ???
stk.pop() — removes the object at the top of the stack stk
⟨en , en−1 , · · · , e2 , e1 ⟩ —> ⟨en−1 , en−2 , · · · , e2 , e1 ⟩
⟨x ⟩ —> ⟨⟩
⟨⟩ —> ???
Like in the case of a queue, “top()” and “pop()” may be combined
into a single operation

C. Aravindan (SNU) Data Structures April 09, 2024 4 / 36


Stack as a wrapper around List

Stack ADT may be easily implemented as a wrapper around a List


stk.push(x) —> lst.insert(x, lst.begin())
stk.top() —> lst.retrieve(lst.begin())
stk.pop() —> lst.delete(lst.begin())

C. Aravindan (SNU) Data Structures April 09, 2024 5 / 36


Stack as a wrapper around List

Stack ADT may be easily implemented as a wrapper around a List


stk.push(x) —> lst.insert(x, lst.begin())
stk.top() —> lst.retrieve(lst.begin())
stk.pop() —> lst.delete(lst.begin())
Using the ’begin’ position of list as ’top’ of stack may not be a good
idea (why?)

C. Aravindan (SNU) Data Structures April 09, 2024 5 / 36


Stack as a wrapper around List

Stack ADT may be easily implemented as a wrapper around a List


stk.push(x) —> lst.insert(x, lst.begin())
stk.top() —> lst.retrieve(lst.begin())
stk.pop() —> lst.delete(lst.begin())
Using the ’begin’ position of list as ’top’ of stack may not be a good
idea (why?)
However, we may consider using the ’end’ position of list

C. Aravindan (SNU) Data Structures April 09, 2024 5 / 36


Stack as a wrapper around List

Stack ADT may be easily implemented as a wrapper around a List


stk.push(x) —> lst.insert(x, lst.begin())
stk.top() —> lst.retrieve(lst.begin())
stk.pop() —> lst.delete(lst.begin())
Using the ’begin’ position of list as ’top’ of stack may not be a good
idea (why?)
However, we may consider using the ’end’ position of list
We may also directly implement a stack with an underlying array
(implementation will be very similar to that of a list)

C. Aravindan (SNU) Data Structures April 09, 2024 5 / 36


Adapter Pattern

Adapter pattern is where an abstraction is realized as a wrapper


around existing structure

C. Aravindan (SNU) Data Structures April 09, 2024 6 / 36


Adapter Pattern

Adapter pattern is where an abstraction is realized as a wrapper


around existing structure
Stack abstraction can be easily implemented as a wrapper around
array-based implementation of list

C. Aravindan (SNU) Data Structures April 09, 2024 6 / 36


Adapter Pattern

Adapter pattern is where an abstraction is realized as a wrapper


around existing structure
Stack abstraction can be easily implemented as a wrapper around
array-based implementation of list
Why don’t we directly use a list? Why build a wrapper?

C. Aravindan (SNU) Data Structures April 09, 2024 6 / 36


Simple Stack Implementation

Following the adapter pattern, a stack internally maintains a list

C. Aravindan (SNU) Data Structures April 09, 2024 7 / 36


Simple Stack Implementation

Following the adapter pattern, a stack internally maintains a list

c l a s s AdapterStack :

d e f __init__ ( s e l f ) :
s e l f . _items = A r r a y L i s t ( )

C. Aravindan (SNU) Data Structures April 09, 2024 7 / 36


Simple Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’

C. Aravindan (SNU) Data Structures April 09, 2024 8 / 36


Simple Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’

c l a s s AdapterStack :

d e f __len__ ( s e l f ) :
r e t u r n ( l e n ( s e l f . _items ) )

d e f __str__ ( s e l f ) :
r e t u r n ( s t r ( s e l f . _items ) )

C. Aravindan (SNU) Data Structures April 09, 2024 8 / 36


Simple Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’

C. Aravindan (SNU) Data Structures April 09, 2024 9 / 36


Simple Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’

c l a s s AdapterStack :

def isEmpty ( s e l f ) :
r e t u r n ( l e n ( s e l f . _ i t e m s ) == 0 )

d e f push ( s e l f , e l e ) :
s e l f . _ i t e m s . append ( e l e )

C. Aravindan (SNU) Data Structures April 09, 2024 9 / 36


Simple Stack Implementation
It should be straightforward to implement the basic stack methods:
’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’

C. Aravindan (SNU) Data Structures April 09, 2024 10 / 36


Simple Stack Implementation
It should be straightforward to implement the basic stack methods:
’len’, ’str’, ’isEmpty’, ’push’, ’top’, and ’pop’
c l a s s Empty ( E x c e p t i o n ) :
pass

c l a s s AdapterStack :

def top ( s e l f ) :
i f ( l e n ( s e l f . _ i t e m s ) == 0 ) :
r a i s e Empty ( " S t a c k ␣ i s ␣ empty ! " )
r e t u r n s e l f . _item . l a s t i t e m ( )

d e f pop ( s e l f ) :
i f ( l e n ( s e l f . _ i t e m s ) == 0 ) :
r a i s e Empty ( " S t a c k ␣ i s ␣ empty ! " )
r e t u r n s e l f . _ i t e m s . pop ( )
C. Aravindan (SNU) Data Structures April 09, 2024 10 / 36
Array-based Stack Implementation

C. Aravindan (SNU) Data Structures April 09, 2024 11 / 36


Array-based Stack Implementation

Array-based stack implementation is very similar to that of list


implementation

C. Aravindan (SNU) Data Structures April 09, 2024 12 / 36


Array-based Stack Implementation

Array-based stack implementation is very similar to that of list


implementation

import ctypes

c l a s s ArrayStack :

d e f __init__ ( s e l f , cap =16):


s e l f . _top = 0
s e l f . _ c a p a c i t y = cap
s e l f . _ i t e m s = ( c t y p e s . p y _ o b j e c t ∗ cap ) ( )

C. Aravindan (SNU) Data Structures April 09, 2024 12 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

C. Aravindan (SNU) Data Structures April 09, 2024 13 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

c l a s s ArrayStack :

d e f __len__ ( s e l f ) :
r e t u r n s e l f . _top

def isEmpty ( s e l f ) :
r e t u r n ( s e l f . _top == 0 )

C. Aravindan (SNU) Data Structures April 09, 2024 13 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

C. Aravindan (SNU) Data Structures April 09, 2024 14 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

c l a s s ArrayStack :

d e f push ( s e l f , i t e m ) :
i f ( s e l f . _top == s e l f . _ c a p a c i t y ) :
s e l f . _ r e s i z e (2 ∗ s e l f . _capacity )
s e l f . _ i t e m s [ s e l f . _top ] = i t e m
s e l f . _top += 1

C. Aravindan (SNU) Data Structures April 09, 2024 14 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

C. Aravindan (SNU) Data Structures April 09, 2024 15 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

c l a s s ArrayStack :

def top ( s e l f ) :
i f ( s e l f . _top == 0 ) :
r a i s e Empty ( " S t a c k ␣ i s ␣ empty ! " )
r e t u r n s e l f . _ i t e m s [ s e l f . _top − 1 ]

C. Aravindan (SNU) Data Structures April 09, 2024 15 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

C. Aravindan (SNU) Data Structures April 09, 2024 16 / 36


Array-based Stack Implementation

It should be straightforward to implement the basic stack methods:


’len’, ’str’, ’push’, ’pop’, ’top’, ’isEmpty’

c l a s s ArrayStack :

d e f pop ( s e l f ) :
i f ( s e l f . _top == 0 ) :
r a i s e Empty ( " S t a c k ␣ i s ␣ empty ! " )
i t e m = s e l f . _ i t e m s [ s e l f . _top − 1 ]
s e l f . _top −= 1
s e l f . _ i t e m s [ s e l f . _top ] = None
i f ( s e l f . _top < ( s e l f . _ c a p a c i t y // 4 ) ) :
s e l f . _ r e s i z e ( s e l f . _ c a p a c i t y // 2 )
r e t u r n item

C. Aravindan (SNU) Data Structures April 09, 2024 16 / 36


Queue

Queue, as the name suggests, is a special kind of a list where


insertions happen only at the end and deletions happen only at the
front
It has only two recognized positions namely “front” and “last”
It is also referred to as First-in-First-out (FIFO) structure

C. Aravindan (SNU) Data Structures April 09, 2024 17 / 36


Queue Operations

q = Queue() — creates and returns a new Queue structure


q.isEmpty() — returns “TRUE” if q is empty and returns “FALSE”
otherwise
q.clear(q) — removes all the objects in q and resets it to an empty
queue

C. Aravindan (SNU) Data Structures April 09, 2024 18 / 36


Enqueue

q.enqueue(x) — add the object x to the Queue q


⟨⟩ —> ⟨x ⟩
⟨e1 , e2 , · · · , en ⟩ —> ⟨e1 , e2 , · · · , en , x ⟩

C. Aravindan (SNU) Data Structures April 09, 2024 19 / 36


Enqueue

q.enqueue(x) — add the object x to the Queue q


⟨⟩ —> ⟨x ⟩
⟨e1 , e2 , · · · , en ⟩ —> ⟨e1 , e2 , · · · , en , x ⟩
There may be a capacity limit for a queue and in that case, enqueue
may not always succeed

C. Aravindan (SNU) Data Structures April 09, 2024 19 / 36


Front and Dequeue

q.front() — returns the first object in the queue q (q is NOT


modified!)
⟨e1 , e2 , · · · , en ⟩ —> e1
⟨⟩ —> ???

C. Aravindan (SNU) Data Structures April 09, 2024 20 / 36


Front and Dequeue

q.front() — returns the first object in the queue q (q is NOT


modified!)
⟨e1 , e2 , · · · , en ⟩ —> e1
⟨⟩ —> ???
q.dequeue() — removes the first object from the queue q
⟨e1 , e2 , · · · , en ⟩ —> ⟨e2 , · · · , en ⟩
⟨x ⟩ —> ⟨⟩
⟨⟩ —> ???

C. Aravindan (SNU) Data Structures April 09, 2024 20 / 36


Front and Dequeue

q.front() — returns the first object in the queue q (q is NOT


modified!)
⟨e1 , e2 , · · · , en ⟩ —> e1
⟨⟩ —> ???
q.dequeue() — removes the first object from the queue q
⟨e1 , e2 , · · · , en ⟩ —> ⟨e2 , · · · , en ⟩
⟨x ⟩ —> ⟨⟩
⟨⟩ —> ???
It is also possible to combine both Front and Dequeue into a single
operation
q.dequeue() — removes and returns the first object from the q

C. Aravindan (SNU) Data Structures April 09, 2024 20 / 36


Queue as a wrapper around List

Queue may be easily implemented as a wrapper around a List

C. Aravindan (SNU) Data Structures April 09, 2024 21 / 36


Queue as a wrapper around List

Queue may be easily implemented as a wrapper around a List


q.enqueue(x) —> lst.insert(x, lst.end())

C. Aravindan (SNU) Data Structures April 09, 2024 21 / 36


Queue as a wrapper around List

Queue may be easily implemented as a wrapper around a List


q.enqueue(x) —> lst.insert(x, lst.end())
q.front() —> lst.retrieve(lst.begin())

C. Aravindan (SNU) Data Structures April 09, 2024 21 / 36


Queue as a wrapper around List

Queue may be easily implemented as a wrapper around a List


q.enqueue(x) —> lst.insert(x, lst.end())
q.front() —> lst.retrieve(lst.begin())
q.dequeue() —> lst.delete(lst.begin())

C. Aravindan (SNU) Data Structures April 09, 2024 21 / 36


Adapter Pattern

Like stack, queue abstraction can also be implemented using the


adapter pattern — as a wrapper around python list

C. Aravindan (SNU) Data Structures April 09, 2024 22 / 36


Adapter Pattern

Like stack, queue abstraction can also be implemented using the


adapter pattern — as a wrapper around python list
But, is it a good idea to do so?

C. Aravindan (SNU) Data Structures April 09, 2024 22 / 36


Circular Array

C. Aravindan (SNU) Data Structures April 09, 2024 23 / 36


Queue Full and Queue Empty Conditions

C. Aravindan (SNU) Data Structures April 09, 2024 24 / 36


Array-based Queue Implementation

Queue abstraction can be implemented by viewing the underlying


array as a ‘circular array’

C. Aravindan (SNU) Data Structures April 09, 2024 25 / 36


Array-based Queue Implementation

Queue abstraction can be implemented by viewing the underlying


array as a ‘circular array’

import ctypes

c l a s s CircArrayQueue :

d e f __init__ ( s e l f , cap =256):


s e l f . _ c a p a c i t y = cap
s e l f . _front = 0
s e l f . _rear = 0
s e l f . _ i t e m s = ( c t y p e s . p y _ o b j e c t ∗ cap ) ( )

C. Aravindan (SNU) Data Structures April 09, 2024 25 / 36


Array-based Queue Implementation

We need a private method to find the ’next position’, when the array
is viewed as a ‘circular array’

C. Aravindan (SNU) Data Structures April 09, 2024 26 / 36


Array-based Queue Implementation

We need a private method to find the ’next position’, when the array
is viewed as a ‘circular array’

c l a s s CircArrayQueue :

d e f _next ( pos ) :
r e t u r n ( ( pos + 1) % s e l f . _c ap ac it y )

C. Aravindan (SNU) Data Structures April 09, 2024 26 / 36


Array-based Queue Implementation

As discussed, it should be easy to check if the queue is empty or full

C. Aravindan (SNU) Data Structures April 09, 2024 27 / 36


Array-based Queue Implementation

As discussed, it should be easy to check if the queue is empty or full

c l a s s CircArrayQueue :

def i s F u l l ( s e l f ) :
r e t u r n ( s e l f . _ f r o n t == s e l f . _next ( s e l f . _ r e a r )

def isEmpty ( s e l f ) :
r e t u r n ( s e l f . _ f r o n t == s e l f . _ r e a r )

C. Aravindan (SNU) Data Structures April 09, 2024 27 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

C. Aravindan (SNU) Data Structures April 09, 2024 28 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

c l a s s CircArrayQueue :

d e f enqueue ( s e l f , i t e m ) :
i f ( s e l f . _ f r o n t == s e l f . _next ( s e l f . _ r e a r ) ) :
r a i s e F u l l ( " The␣ queue ␣ i s ␣ a l r e a d y ␣ f u l l ! " )
s e l f . _items [ s e l f . _rear ] = item
s e l f . _ r e a r = s e l f . _next ( s e l f . _ r e a r )

C. Aravindan (SNU) Data Structures April 09, 2024 28 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

C. Aravindan (SNU) Data Structures April 09, 2024 29 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

c l a s s CircArrayQueue :

def front ( s e l f ) :
i f ( s e l f . _ f r o n t == s e l f . _ r e a r ) :
r a i s e Empty ( " The␣ queue ␣ i s ␣ empty ! " )
r e t u r n s e l f . _items [ s e l f . _front ]

C. Aravindan (SNU) Data Structures April 09, 2024 29 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

C. Aravindan (SNU) Data Structures April 09, 2024 30 / 36


Array-based Queue Implementation

The core queue operations should also be easy to implement

c l a s s CircArrayQueue :

d e f dequeue ( s e l f ) :
i f ( s e l f . _ f r o n t == s e l f . _ r e a r ) :
r a i s e Empty ( " The␣ queue ␣ i s ␣ empty ! " )
item = s e l f . _items [ s e l f . _front ]
s e l f . _ i t e m s [ s e l f . _ f r o n t ] = None
s e l f . _ f r o n t = s e l f . _next ( s e l f . _ f r o n t )
r e t u r n item

C. Aravindan (SNU) Data Structures April 09, 2024 30 / 36


Array-based Queue Implementation

How do we find the length of the current queue?

C. Aravindan (SNU) Data Structures April 09, 2024 31 / 36


Array-based Queue Implementation

How do we find the length of the current queue?


If ‘rear’ is ahead of ’front’, then the length is rear − front

C. Aravindan (SNU) Data Structures April 09, 2024 31 / 36


Array-based Queue Implementation

How do we find the length of the current queue?


If ‘rear’ is ahead of ’front’, then the length is rear − front
Else, length is capacity − (front − rear)

C. Aravindan (SNU) Data Structures April 09, 2024 31 / 36


Array-based Queue Implementation

How do we find the length of the current queue?


If ‘rear’ is ahead of ’front’, then the length is rear − front
Else, length is capacity − (front − rear)

c l a s s CircArrayQueue :

d e f __len__ ( s e l f ) :
i f ( s e l f . _ f r o n t <= s e l f . _ r e a r ) :
return ( s e l f . _rear − s e l f . _front )
else :
return s e l f . _capacity − ( s e l f . _front − s e l

C. Aravindan (SNU) Data Structures April 09, 2024 31 / 36


Double-Ended Queues

Double-ended Queue (pronounced as “deck”) is an abstraction where


enqueue and dequeue operations are possible at both the ends

C. Aravindan (SNU) Data Structures April 09, 2024 32 / 36


Double-Ended Queues

Double-ended Queue (pronounced as “deck”) is an abstraction where


enqueue and dequeue operations are possible at both the ends
It is a generalization of both stack and queue abstractions, since it
can also be viewed as permitting push and pop operations at both the
ends

C. Aravindan (SNU) Data Structures April 09, 2024 32 / 36


Double-Ended Queues

deq.addFirst(item)
deq.addLast(item)
deq.deleteFirst()
deq.deleteLast()
deq.first()
deq.last()
deq.isEmpty()
deq.isFull() [This is required only when the capacity is fixed]
len(deq)

C. Aravindan (SNU) Data Structures April 09, 2024 33 / 36


Double-Ended Queues

Implementation of double-ended queue is left as an exercise!

C. Aravindan (SNU) Data Structures April 09, 2024 34 / 36


Summary

We have discussed array based implementations of Stack and Queue


ADTs

C. Aravindan (SNU) Data Structures April 09, 2024 35 / 36


What next?

We will explore link-based implementations of List, Stack, and Queue


ADTs
We will look at some of the applications of Lists, Stacks, and Queues

C. Aravindan (SNU) Data Structures April 09, 2024 36 / 36

You might also like