Stack and Queue
Stack and Queue
Stack is an abstract data type with a bounded (predefined) capacity. It is a simple data structure
that allows adding and removing elements in a particular order. Every time an element is added,
it goes on the top of the stack, the only element that can be removed is the element that was at
the top of the stack, just like a pile of objects.
3. push() function is used to insert new elements into the Stack and pop() function is used to
delete an element from the stack. Both insertion and deletion are allowed at only one end of
Applications of Stack
The simplest application of a stack is to reverse a word. You push a given word to stack - letter
by letter - and then pop letters from the stack.
There are other uses also like : Parsing, Expression Conversion(Infix to Postfix, Postfix to
Prefix etc) and many more.
Implementation of Stack
Stack can be easily implemented using an Array or a Linked List. Arrays are quick, but are
limited in size and Linked List requires overhead to allocate, link, unlink, and deallocate, but is
not limited in size. Here we will implement Stack using array.
2. If the stack is full,then print error of overflow and exit the program.
3. If the stack is not full,then increment the top and add the element .
2. If the stack is empty, then print error of underflow and exit the program.
3. If the stack is not empty, then print the element at the top and decrement the top.
Class Stack
{
int top;
public:
Stack()
top = -1;
};
void Stack::push(int x)
else
a[++top] = x;
int Stack::pop()
if(top < 0)
return 0;
else
int d = a[top--];
return d;
}
}
void Stack::isEmpty()
if(top < 0)
else
-1 Stack is Empty
Analysis of Stacks
Below mentioned are the time complexities for various operations that can be performed on the
Stack data structure.
1. Like Stack, Queue is also an ordered list of elements of similar data types.
the new element in the queue must be removed, to remove the new element.
4. peek( ) function is oftenly used to return the value of first element without
dequeuing it.
Applications of Queue
Queue, as the name suggests is used whenever we need to manage any group of
objects in an order in which the first one coming in, also gets out first while the
others wait for their turn, like in the following scenarios :
scheduling etc.
2. In real life scenario, Call Center phone systems uses Queues to hold people
Implementation of Queue
Queue can be implemented using an Array, Stack or Linked List. The easiest way of
implementing a queue is by using an Array. Initially the head(FRONT) and
the tail(REAR) of the queue points at the first index of the array (starting the index of
array from 0). As we add elements to the queue, the tail keeps on moving ahead,
always pointing to the position where the next element will be inserted, while the
head remains at the first index.
When we remove an element from Queue, we can follow two possible approaches
(mentioned [A] and [B] in above diagram). In [A] approach, we remove the element
at head position, and then one by one shift all the other elements in forward
position. In approach [B] we remove the element from headposition and then
move head to the next position.
In approach [A] there is an overhead of shifting the elements one position forward
every time we remove the first element. In approach [B] there is no such overhead,
but whenever we move head one position ahead, after removal of first element, the
size on Queue is reduced by one space each time.
2. If the queue is full, then print overflow error and exit the program.
3. If the queue is not full, then increment the tail and add the element.
2. If the queue is empty, then print underflow error and exit the program.
3. If the queue is not empty, then print the element at the head and increment the
head.
class Queue
int a[100];
public:
Queue()
int dequeue();
void display();
else
a[++rear] = x;
int i;
To implement approach [A], you simply need to change the dequeue method, and
include a for loop which will shift all the remaining elements one position.
return a[0]; //returning first element
a[i]= a[i+1];
tail--;
Analysis of Queue
Enqueue : O(1)
Dequeue : O(1)
Size : O(1)
int Queue :: dequeue() {
while(S1.isEmpty()) {
x = S1.pop();
S2.push();
}
//removing the element
x = S2.pop();
while(!S2.isEmpty()) {
x = S2.pop();
S1.push(x);
}
return x;
}
Stack ADT
What is a Stack?
Stack is a linear data structure in which the insertion and deletion
operations are performed at only one end. In a stack, adding and removing
of elements are performed at single position which is known as "top". That
means, new element is added at top of the stack and an element is removed
from the top of the stack. In stack, the insertion and deletion operations are
performed based on LIFO (Last In First Out) principle.
In a stack, the insertion operation is performed using a function
called "push" and deletion operation is performed using a function
called "pop".
In the figure, PUSH and POP operations are performed at top position in the
stack. That means, both the insertion and deletion operations are
performed at one end (i.e., at Top)
"A Collection of similar data items in which both insertion and deletion
operations are performed based on LIFO principle".
Example
If we want to create a stack by inserting 10,45,12,16,35 and 50. Then 10
becomes the bottom most element and 50 is the top most element. Top is at
50 as shown in the image below...
Operations on a Stack
The following operations are performed on the stack...
Stack data structure can be implement in two ways. They are as follows...
1. Using Array
2. Using Linked List
When stack is implemented using array, that stack can organize only limited
number of elements. When stack is implemented using linked list, that stack
can organize unlimited number of elements.
A stack data structure can be implemented using one dimensional array. But
stack implemented using array, can store only fixed number of data values.
This implementation is very simple, just define a one dimensional array of
specific size and insert or delete the values into that array by using LIFO
principle with the help of a variable 'top'. Initially top is set to -1.
Whenever we want to insert a value into the stack, increment the top value
by one and then insert. Whenever we want to delete a value from the stack,
then delete the top value and decrement the top value by one.
#define SIZE 10
void push(int);
void pop();
void display();
void main()
{
int value, choice;
clrscr();
while(1){
printf("\n\n***** MENU *****\n");
printf("1. Push\n2. Pop\n3. Display\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d",&value);
push(value);
break;
case 2: pop();
break;
case 3: display();
break;
case 4: exit(0);
default: printf("\nWrong selection!!! Try again!!!");
}
}
}
void push(int value){
if(top == SIZE-1)
printf("\nStack is Full!!! Insertion is not possible!!!");
else{
top++;
stack[top] = value;
printf("\nInsertion success!!!");
}
}
void pop(){
if(top == -1)
printf("\nStack is Empty!!! Deletion is not possible!!!");
else{
printf("\nDeleted : %d", stack[top]);
top--;
}
}
void display(){
if(top == -1)
printf("\nStack is Empty!!!");
else{
int i;
printf("\nStack elements are:\n");
for(i=top; i>=0; i--)
printf("%d\n",stack[i]);
}
}
Output
Stack using Linked List
The major problem with the stack implemented using array is, it works only
for fixed number of data values. That means the amount of data must be
specified at the beginning of the implementation itself. Stack implemented
using array is not suitable, when we don't know the size of data which we
are going to use. A stack data structure can be implemented by using linked
list data structure. The stack implemented using linked list can work for
unlimited number of values. That means, stack implemented using linked
list works for variable size of data. So, there is no need to fix the size at the
beginning of the implementation. The Stack implemented using linked list
can organize as many data values as we want.
In above example, the last inserted node is 99 and the first inserted node is
25. The order of elements inserted is 25, 32,50 and 99.
Operations
To implement stack using linked list, we need to set the following things
before implementing actual operations.
Step 1: Include all the header files which are used in the program.
And declare all the user defined functions.
Step 2: Define a 'Node' structure with two members data and next.
Step 3: Define a Node pointer 'top' and set it to NULL.
Step 4: Implement the main method by displaying Menu with list of
operations and make suitable function calls in the mainmethod.
struct Node
{
int data;
struct Node *next;
}*top = NULL;
void push(int);
void pop();
void display();
void main()
{
int choice, value;
clrscr();
printf("\n:: Stack using Linked List ::\n");
while(1){
printf("\n****** MENU ******\n");
printf("1. Push\n2. Pop\n3. Display\n4. Exit\n");
printf("Enter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d", &value);
push(value);
break;
case 2: pop(); break;
case 3: display(); break;
case 4: exit(0);
default: printf("\nWrong selection!!! Please try again!!!\n");
}
}
}
void push(int value)
{
struct Node *newNode;
newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
if(top == NULL)
newNode->next = NULL;
else
newNode->next = top;
top = newNode;
printf("\nInsertion is Success!!!\n");
}
void pop()
{
if(top == NULL)
printf("\nStack is Empty!!!\n");
else{
struct Node *temp = top;
printf("\nDeleted element: %d", temp->data);
top = temp->next;
free(temp);
}
}
void display()
{
if(top == NULL)
printf("\nStack is Empty!!!\n");
else{
struct Node *temp = top;
while(temp->next != NULL){
printf("%d--->",temp->data);
temp = temp -> next;
}
printf("%d--->NULL",temp->data);
}
}
Output
Expressions
What is an Expression?
In any programming language, if we want to perform any calculation or to
frame a condition etc., we use a set of symbols to perform the task. These
set of symbols makes an expression.
Expression Types
Based on the operator position, expressions are divided into THREE types.
They are as follows...
1. Infix Expression
2. Postfix Expression
3. Prefix Expression
Infix Expression
In infix expression, operator is used in between operands.
Example
Postfix Expression
In postfix expression, operator is used after operands. We can say that
"Operator follows the Operands".
The general structure of Postfix expression is as follows...
Example
Prefix Expression
In prefix expression, operator is used before operands. We can say that
"Operands follows the Operator".
Example
Any expression can be represented using the above three different types of
expressions. And we can convert an expression from one form to another
form like Infix to Postfix, Infix to Prefix, Prefix to Postfix and vice versa.
Expression Conversion
To convert any Infix expression into Postfix or Prefix expression we can use
the following procedure...
Example
Consider the following Infix Expression to be converted into Postfix
Expression...
D=A+B*C
Step 1: The Operators in the given Infix Expression : = , + , *
Step 2: The Order of Operators according to their preference : * , + ,
=
Step 3: Now, convert the first operator * ----- D = A + B C *
Step 4: Convert the next operator + ----- D = A BC* +
Step 5: Convert the next operator = ----- D ABC*+ =
DABC*+=
Infix to Postfix Conversion using Stack
Data Structure
To convert Infix Expression into Postfix Expression using a stack data
structure, We can use the following steps...
1. Read all the symbols one by one from left to right in the given
Infix Expression.
2. If the reading symbol is operand, then directly print it to the
result (Output).
3. If the reading symbol is left parenthesis '(', then Push it on to the
Stack.
4. If the reading symbol is right parenthesis ')', then Pop all the
contents of stack until respective left parenthesis is poped and
print each poped symbol to the result.
5. If the reading symbol is operator (+ , - , * , / etc.,), then Push it
on to the Stack. However, first pop the operators which are
already on the stack that have higher or equal precedence than
current operator and print them to the result.
Example
Consider the following Infix Expression...
(A+B)*(C-D)
The given infix expression can be converted into postfix expression using
Stack data Structure as follows...
The final Postfix Expression is as follows...
AB+CD-*
1. Read all the symbols one by one from left to right in the given
Postfix Expression
2. If the reading symbol is operand, then push it on to the Stack.
3. If the reading symbol is operator (+ , - , * , / etc.,), then perform
TWO pop operations and store the two popped oparands in two
different variables (operand1 and operand2). Then perform
reading symbol operation using operand1 and operand2 and push
result back on to the Stack.
4. Finally! perform a pop operation and display the popped value as
final result.
Example
Consider the following Expression...
Queue ADT
What is a Queue?
Queue is a linear data structure in which the insertion and deletion
operations are performed at two different ends. In a queue data structure,
adding and removing of elements are performed at two different positions.
The insertion is performed at one end and deletion is performed at other
end. In a queue data structure, the insertion operation is performed at a
position which is known as 'rear' and the deletion operation is performed at
a position which is known as 'front'. In queue data structure, the insertion
and deletion operations are performed based on FIFO (First In First
Out) principle.
Example
Queue after inserting 25, 30, 51, 60 and 85.
Operations on a Queue
The following operations are performed on a queue data structure...
1. Using Array
2. Using Linked List
When a queue is implemented using array, that queue can organize only
limited number of elements. When a queue is implemented using linked list,
that queue can organize unlimited number of elements.
Step 1: Include all the header files which are used in the program
and define a constant 'SIZE' with specific value.
Step 2: Declare all the user defined functions which are used in
queue implementation.
Step 3: Create a one dimensional array with above defined SIZE (int
queue[SIZE])
Step 4: Define two integer variables 'front' and 'rear' and initialize
both with '-1'. (int front = -1, rear = -1)
Step 5: Then implement main method by displaying menu of
operations list and make suitable function calls to perform operation
selected by the user on queue.
enQueue(value) - Inserting value into the queue
In a queue data structure, enQueue() is a function used to insert a new
element into the queue. In a queue, the new element is always inserted
at rear position. The enQueue() function takes one integer value as
parameter and inserts that value into the queue. We can use the following
steps to insert an element into the queue...
void enQueue(int);
void deQueue();
void display();
void main()
{
int value, choice;
clrscr();
while(1){
printf("\n\n***** MENU *****\n");
printf("1. Insertion\n2. Deletion\n3. Display\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d",&value);
enQueue(value);
break;
case 2: deQueue();
break;
case 3: display();
break;
case 4: exit(0);
default: printf("\nWrong selection!!! Try again!!!");
}
}
}
void enQueue(int value){
if(rear == SIZE-1)
printf("\nQueue is Full!!! Insertion is not possible!!!");
else{
if(front == -1)
front = 0;
rear++;
queue[rear] = value;
printf("\nInsertion success!!!");
}
}
void deQueue(){
if(front == rear)
printf("\nQueue is Empty!!! Deletion is not possible!!!");
else{
printf("\nDeleted : %d", queue[front]);
front++;
if(front == rear)
front = rear = -1;
}
}
void display(){
if(rear == -1)
printf("\nQueue is Empty!!!");
else{
int i;
printf("\nQueue elements are:\n");
for(i=front; i<=rear; i++)
printf("%d\t",queue[i]);
}
}
Output
Example
In above example, the last inserted node is 50 and it is pointed by 'rear' and
the first inserted node is 10 and it is pointed by 'front'. The order of
elements inserted is 10, 15, 22 and 50.
Operations
To implement queue using linked list, we need to set the following things
before implementing actual operations.
Step 1: Include all the header files which are used in the program.
And declare all the user defined functions.
Step 2: Define a 'Node' structure with two members data and next.
Step 3: Define two Node pointers 'front' and 'rear' and set both
to NULL.
Step 4: Implement the main method by displaying Menu of list of
operations and make suitable function calls in the main method to
perform user selected operation.
struct Node
{
int data;
struct Node *next;
}*front = NULL,*rear = NULL;
void insert(int);
void delete();
void display();
void main()
{
int choice, value;
clrscr();
printf("\n:: Queue Implementation using Linked List ::\n");
while(1){
printf("\n****** MENU ******\n");
printf("1. Insert\n2. Delete\n3. Display\n4. Exit\n");
printf("Enter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d", &value);
insert(value);
break;
case 2: delete(); break;
case 3: display(); break;
case 4: exit(0);
default: printf("\nWrong selection!!! Please try again!!!\n");
}
}
}
void insert(int value)
{
struct Node *newNode;
newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode -> next = NULL;
if(front == NULL)
front = rear = newNode;
else{
rear -> next = newNode;
rear = newNode;
}
printf("\nInsertion is Success!!!\n");
}
void delete()
{
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else{
struct Node *temp = front;
front = front -> next;
printf("\nDeleted element: %d\n", temp->data);
free(temp);
}
}
void display()
{
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else{
struct Node *temp = front;
while(temp->next != NULL){
printf("%d--->",temp->data);
temp = temp -> next;
}
printf("%d--->NULL\n",temp->data);
}
}
Output
Circular Queue
In a normal Queue Data Structure, we can insert elements until queue
becomes full. But once if queue becomes full, we can not insert the next
element until all the elements are deleted from the queue. For example
consider the queue below...
Now consider the following situation after deleting three elements from the
queue...
This situation also says that Queue is Full and we can not insert the new
element because, 'rear' is still at last position. In above situation, even
though we have empty positions in the queue we can not make use of them
to insert new element. This is the major problem in normal queue data
structure. To overcome this problem we use circular queue data structure.
Step 1: Include all the header files which are used in the program
and define a constant 'SIZE' with specific value.
Step 2: Declare all user defined functions used in circular queue
implementation.
Step 3: Create a one dimensional array with above defined SIZE (int
cQueue[SIZE])
Step 4: Define two integer variables 'front' and 'rear' and initialize
both with '-1'. (int front = -1, rear = -1)
Step 5: Implement main method by displaying menu of operations list
and make suitable function calls to perform operation selected by the
user on circular queue.
void enQueue(int);
void deQueue();
void display();
void main()
{
int choice, value;
clrscr();
while(1){
printf("\n****** MENU ******\n");
printf("1. Insert\n2. Delete\n3. Display\n4. Exit\n");
printf("Enter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("\nEnter the value to be insert: ");
scanf("%d",&value);
enQueue(value);
break;
case 2: deQueue();
break;
case 3: display();
break;
case 4: exit(0);
default: printf("\nPlease select the correct choice!!!\n");
}
}
}
void enQueue(int value)
{
if((front == 0 && rear == SIZE - 1) || (front == rear+1))
printf("\nCircular Queue is Full! Insertion not possible!!!\n");
else{
if(rear == SIZE-1 && front != 0)
rear = -1;
cQueue[++rear] = value;
printf("\nInsertion Success!!!\n");
if(front == -1)
front = 0;
}
}
void deQueue()
{
if(front == -1 && rear == -1)
printf("\nCircular Queue is Empty! Deletion is not possible!!!\n");
else{
printf("\nDeleted element : %d\n",cQueue[front++]);
if(front == SIZE)
front = 0;
if(front-1 == rear)
front = rear = -1;
}
}
void display()
{
if(front == -1)
printf("\nCircular Queue is Empty!!!\n");
else{
int i = front;
printf("\nCircular Queue Elements are : \n");
if(front <= rear){
while(i <= rear)
printf("%d\t",cQueue[i++]);
}
else{
while(i <= SIZE - 1)
printf("%d\t", cQueue[i++]);
i = 0;
while(i <= rear)
printf("%d\t",cQueue[i++]);
}
}
}
Output
Priority Queue
1. R1 : 20 units of time
2. R2 : 22 units of time (R2 must wait till R1 complete - 20 units and
R2 itself requeres 2 units. Total 22 units)
3. R3 : 32 units of time (R3 must wait till R2 complete - 22 units and
R3 itself requeres 10 units. Total 32 units)
4. R4 : 37 units of time (R4 must wait till R3 complete - 35 units and
R4 itself requeres 5 units. Total 37 units)
Here, average waiting time for all requests (R1, R2, R3 and R4) is
(20+22+32+37)/4 ≈ 27 units of time.
That means, if we use a normal queue data structure to serve these requests
the average waiting time for each request is 27 units of time.
1. R2 : 2 units of time
2. R4 : 7 units of time (R4 must wait till R2 complete 2 units and R4
itself requeres 5 units. Total 7 units)
3. R3 : 17 units of time (R3 must wait till R4 complete 7 units and R3
itself requeres 10 units. Total 17 units)
4. R1 : 37 units of time (R1 must wait till R3 complete 17 units and
R1 itself requeres 20 units. Total 37 units)
Here, average waiting time for all requests (R1, R2, R3 and R4) is
(2+7+17+37)/4 ≈ 15 units of time.
From above two situations, it is very clear that, by using second method
server can complete all four requests with very less time compared to the
first method. This is what exactly done by the priority queue.
For example, assume that elements are inserted in the order of 8, 2, 3 and
5. And they are removed in the order 8, 5, 3 and 2.
insert() - New element is added at the end of the queue. This operation
requires O(1) time complexity that means constant time.
For example, assume that elements are inserted in the order of 8, 2, 3 and
5. And they are removed in the order 8, 5, 3 and 2.
Now, let us analyse each operation according to this representation...
insert() - New element is added at the end of the queue with O(1) and for
each insertion we need to update maxIndex with O(1). This operation
requires O(1) time complexity that means constant time.
For example, assume that elements are inserted in the order of 8, 5, 3 and
2. And they are removed in the order 8, 5, 3 and 2.
For example, assume that elements are inserted in the order of 2, 3, 5 and
8. And they are removed in the order 8, 5, 3 and 2.
Now, let us analyse each operation according to this representation...
For example, assume that elements are inserted in the order of 2, 3, 5 and
8. And they are removed in the order 8, 5, 3 and 2.
Now, let us analyse each operation according to this representation...
For example, assume that elements are inserted in the order of 2, 8, 3 and
5. And they are removed in the order 8, 5, 3 and 2.
insert() - New element is added at end the queue with O(1) and update
maxValue reference with O(1). This operation requires O(1)time
complexity.
Min priority queue is also has same representations as Max priority queue
with minimum value removal.