You are on page 1of 33

CSC112

Algorithms and Data Structures

Lecture 13
Stack
Implementation & Applications
Abstract Data Type

• We have looked different implementations of the List data


structures, like Arrays and Linked list
• The interface to the List stayed the same, i.e., add(), get(),
next(), start(), remove() etc.
• The list is thus an abstract data type; we use it without
being concerned with how it is implemented.
• We will publish the interface and keep the freedom to
change the implementation of ADT without effecting users
of the ADT. The C++ classes provide us the ability to
create such ADTs.
Stacks

Stack is a linear data structure which follows a particular order in


which the operations are performed. The order may be LIFO(Last
In First Out) or FILO(First In Last Out).

*LIFO, Linear, Homogeneous, Static/Dynamic, Special purpose DS.


Stacks

A stack is an Abstract Data Type (ADT), commonly used in


most programming languages. It is named stack as it
behaves like a real-world stack, for example – a deck of
cards or a pile of plates, etc.

A real-world stack allows operations at one end only. For


example, we can place or remove an element from the top
of the stack only. Likewise, Stack allows all data operations
at one end only.

This feature makes it LIFO/FILO data structure. Here, the


element which is placed (inserted or added) last, is
accessed first.
Stack Representation
A stack can be implemented by means of Array, and Linked
List. Stack can either be a fixed size one or it may have a
sense of dynamic resizing.
Stack - Basic Operations
Stack operations may involve initializing the stack, using it and
then de-initializing it.
Time complexities of push(), pop(), isEmpty(), isFull and top() all
take O(1) time. We do not run any loop in any of these operations.

push() − Pushing (storing) an element on the stack.


pop() − Removing (accessing) an element from the stack.

top() − get the top data element of the stack, without removing it.

isFull() − check if stack is full.


isEmpty() − check if stack is empty.
Stack - Basic Operations – (PUSH)
Push Operation is the process of putting a new data element onto stack.
Push operation involves a series of steps −

Step 1 − Checks if the stack is full (produces an error and exit)


Step 2 − If the stack is not full, increments top to point next empty space.
Step 3 − Adds data element to the stack location, where top is pointing.
Step 4 − Returns success.
Stack - Basic Operations – (PUSH)

PUSH (Stack, Top, Size, Item)


If Top = Size
Print “Over Flow”
Return
Top = Top + 1
Stack [Top] = Item
Return
Stack - Basic Operations – (POP)
Pop Operation is the procedure of accessing the content while removing it
from the stack.

Step 1 − If the stack is empty, produces an error and exit.


Step 2 − If the stack is not empty, accesses the data element at
which top is pointing.
Step 3 − Decreases the value of top by 1.
Step 4 − Returns success.
Stack - Basic Operations – (POP)

POP(Stack, Top)
If Top = NULL
Print “Stack is empty”
Return
Item = Stack [Top]
Top = Top – 1
Return Item
Stack - Basic Operations – (IsEmpty)
Implementation of IsEmpty() function is slightly different. We
initialize top at -1, as the index in array starts from 0. So we check if
the top is below zero or -1 to determine if the stack is empty.

IsEmpty()
If Top = -1
Return True
Else
Return False
End
Stack Operations

top 1
top 7 7
top 5 5 5
top 2 2 2 2
push(2) push(5) push(7) push(1)

top 21
top 7 7 top 7
5 5 5 top 5
2 2 2 2 top 2
1 pop() push(21) 21 pop() 7 pop() 5 pop()
Stack Implementation: Array

• Worst case for insertion and deletion from an array when insert
and delete from the beginning: shift elements to the left.

• Best case for insert and delete is at the end of the array – no need
to shift any elements.

• Implement push() and pop() by inserting and deleting at the end of


an array.
Stack using an Array
bool IsEmpty() {
if (top == -1) return true;
else return false;
}

bool IsFull() {
if(top == MAXSIZE) return true;
else return false;
}

int Top() {
return stack[top];
}
Stack using an Array
int push(int data)
{
if( IsFull() )
{
cout<<"Stack is full.";
}
else
{
top = top + 1;
stack[top] = data;
}
}
Stack using an Array
int pop()
{
if(IsEmpty())
{
cout<<“Stack is empty.";
}
else
{
int data = stack[top];
top = top - 1;
return data;
}
}
Stack using an Array
void main() {
push(5);
push(9);
push(15);

cout << "Element at top of the stack:“, Top());

while( !IsEmpty()) {
int data = pop();
cout<<data;
}
}
Stack using an Array

Pros:
Easy to implement.
Memory is saved as pointers are not involved.

Cons:
It is not dynamic.
It doesn’t grow and shrink depending on needs at runtime.
Stack Using Linked List

We can avoid the size limitation of a stack implemented


with an array by using a linked list to hold the stack
elements.

Pros:
The linked list implementation of stack can grow and shrink
according to the needs at runtime.

Cons:
Requires extra memory due to involvement of pointers.
Stack Using Linked List

• For a linked list, insert and deletion at start takes constant


time using the head and current pointers respectively.

• Inserting and Removing an element at the end required


traversing the list.

• Make sense to place stack elements at the start of the list


because insert and removal are constant time.
Stack Using Linked List
head
top 1
1 7 5 2
7
5
2
head

1 7 5 2
top 7
5
2
head
top 9
7 5 2
7
5
newNode 99
2

push(9)
Stack - Basic Operations – (PUSH)
Push (Item, Top)
Create new_node
Set new_node -> Data = item
If (Top = NULL)
a. new_node -> next = NULL
b. Top = new_node
Else
a. new_node -> next = TOP
b. Top = new_node
Return
Stack: Array or List
• Since both implementations support stack operations in
constant time, any reason to choose one over the
other?
• Allocating and deallocating memory for list nodes does
take more time than preallocated array.
• List uses only as much memory as required by the
nodes; array requires allocation ahead of time.
• List pointers (head, next) require extra memory.
• Array has an upper limit; List is limited by dynamic
memory allocation.
Stack - Applications
• Parsing, Nested Structures, Recursion, Function Calling
• Balancing of symbols (Expression Evaluation)
• Infix to Postfix /Prefix conversion
• Redo-undo features at many places like editors, photoshop.
• Forward and backward feature in web browsers
• Used in many algorithms like Tower of Hanoi, tree,
traversals, stock span problem, histogram problem.
• Other applications can be Backtracking, Knight tour problem, rat
in a maze, N queen problem and sudoku solver
Expression Parsing
The way to write arithmetic expression is known as a notation.
An arithmetic expression can be written in three different but
equivalent notations, i.e., without changing the essence or
output of an expression. These notations are −

• Infix Notation
• Prefix (Polish) Notation
• Postfix (Reverse-Polish) Notation
Use of Stack
• Example of use: prefix, infix, postfix expressions.

• Consider the expression A+B: we think of applying the


operator “+” to the operands A and B.

• “+” is termed a binary operator: it takes two operands.


• Writing the sum as A+B is called the infix form of the
expression.
Infix Notation
Writing the sum as A+B is called the infix form of the expression;
e.g. a - b + c, where operators are used in-between operands. It
is easy for us humans to read, write, and speak in infix notation
but the same does not go well with computing devices. An
algorithm to process infix notation could be difficult and costly in
terms of time and space consumption.
Prefix Notation
In this notation, operator is prefixed to operands, i.e. operator is
written ahead of operands. For example, +ab. This is equivalent
to its infix notation a + b. Prefix notation is also known as Polish
Notation.
Postfix Notation
This notation style is known as Reversed Polish Notation. In this
notation style, the operator is postfixed to the operands i.e., the
operator is written after the operands. For example, ab+. This is
equivalent to its infix notation a + b.
Example
Sr. No. Infix Notation Prefix Notation Postfix Notation

1 a+b +ab ab+

2 (a + b) ∗ c ∗+abc ab+c∗

3 a ∗ (b + c) ∗a+bc abc+∗

4 a/b+c/d +/ab/cd ab/cd/+

5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗

6 ((a + b) ∗ c) - d -∗+abcd ab+c∗d-


Parsing Expressions
Precedence and Associativity determines the order of evaluation
of an expression.

Precedence
When an operand is in between two different operators, which
operator will take the operand first, is decided by the
precedence of an operator over others.
For example multiplication operation has precedence over
addition, b * c will be evaluated first
Parsing Expressions
Associativity
Associativity describes the rule where operators with the same
precedence appear in an expression.
For example, in expression a + b − c, both + and – have the same
precedence, and both + and − are left associative, so the
expression will be evaluated as (a + b) − c.
Sr. No. Operator Precedence Associativity
1 Exponentiation ^ Highest Right Associative
2 Multiplication ( ∗ ) & Division ( / ) Second Left Associative
Highest
3 Addition ( + ) & Subtraction ( − ) Lowest Left Associative

*The order can be altered by using parenthesis.


Postfix Evaluation Algorithm
Step 1 − scan the expression from left to right
Step 2 − if it is an operand push it to stack
Step 3 − if it is an operator pull operand from stack and perform
operation
Step 4 − store the output of step 3, back to stack
Step 5 − scan the expression until all operands are consumed
Step 6 − pop the stack and perform operation

You might also like