Data Structure Notes
Data Structure Notes
Data structure is a storage that is used to store and organize data. It is a way of arranging data
on a computer so that it can be accessed and updated efficiently.
Depending on your requirement and project, it is important to choose the right data structure
for your project. For example, if you want to store data sequentially in the memory, then you
can go for the Array data structure.
In an array, elements in memory are arranged in continuous memory. All the elements of an
array are of the same type. And, the type of elements that can be stored in the form of arrays
is determined by the programming language.
In stack data structure, elements are stored in the LIFO principle. That is, the last element
stored in a stack will be removed first.
It works just like a pile of plates where the last plate kept on the pile will be removed first.
In a stack, operations can be perform only from one end (top here).
3. Queue Data Structure
Unlike stack, the queue data structure works in the FIFO principle where first element stored
in the queue will be removed first.
It works just like a queue of people in the ticket counter where first person on the queue will
get the ticket first.
A linked list
Non-linear data structures are further divided into graph and tree based data structures.
1. Graph Data Structure
In graph data structure, each node is called vertex and each vertex is connected to other
vertices through edges.
Graph data structure example
Popular Graph Based Data Structures:
Spanning Tree and Minimum Spanning Tree
Strongly Connected Components
Adjacency Matrix
Adjacency List
The data items are arranged in sequential The data items are arranged in non-
order, one after the other. sequential order (hierarchical manner).
All the items are present on the single The data items are present at different
layer. layers.
It can be traversed on a single run. That is, It requires multiple runs. That is, if we
if we start from the first element, we can start from the first element it might not be
traverse all the elements sequentially in a possible to traverse all the elements in a
single pass. single pass.
Array
Definition
o Arrays are defined as the collection of similar type of data items stored at contiguous memory
locations.
o Arrays are the derived data type in C programming language which can store the primitive
type of data such as int, char, double, float, etc.
o Array is the simplest data structure where each data element can be randomly accessed by
using its index number.
o For example, if we want to store the marks of a student in 6 subjects, then we don't need to
define different variable for the marks in different subject. Instead of that, we can define an
array which can store the marks in each subject at the contiguous memory locations.
The array marks [10] defines the marks of the student in 10 different subjects where each
subject marks are located at a particular subscript in the array i.e. marks [0] denotes the
marks in first subject, marks [1] denotes the marks in 2nd subject and so on.
1. Each element is of same data type and carries a same size i.e. int = 4 bytes.
2. Elements of the array are stored at contiguous memory locations where the first element is
stored at the smallest memory location.
3. Elements of the array can be randomly accessed since we can calculate the address of each
element of the array with the given base address and the size of data element.
For example, in C language, the syntax of declaring an array is like following:
int arr[10]; char arr[10]; float arr[5];
In the following example, we have marks of a student in six different subjects. The problem
intends to calculate the average of all the marks of the student.
In order to illustrate the importance of array, we have created two programs, one is without
using array and other involves the use of array to store marks.
Time and space complexity of various array operations are described in the following table.
Time Complexity
Space Complexity
In array, space complexity for worst case is O (n).
Advantages of Array
o Array provides the single name for the group of variables of the same type therefore, it is
easy to remember the name of all the elements of an array.
o Traversing an array is a very simple process, we just need to increment the base address of
the array in order to visit each element one by one.
o Any element in the array can be directly accessed by using the index.
1. 0 (zero - based indexing) : The first element of the array will be arr[0].
2. 1 (one - based indexing) : The first element of the array will be arr[1].
3. n (n - based indexing) : The first element of the array can reside at any random index number.
In the following image, we have shown the memory allocation of an array arr of size 5. The
array follows 0-based indexing approach. The base address of the array is 100th byte. This
will be the address of arr[0]. Here, the size of int is 4 bytes therefore each element will take 4
bytes in the memory.
In 0 based indexing, If the size of an array is n then the maximum index number, an element
can have is n-1. However, it will be n if we use 1 based indexing.
Example:
1. In an array, A[-10 ..... +2 ], Base address (BA) = 999, size of an element = 2 bytes,
2. find the location of A[-1].
3. L(A[-1]) = 999 + [(-1) - (-10)] x 2
4. = 999 + 18
5. = 1017
The following example illustrate, how the array can be passed to a function.
Example:
1. #include <stdio.h>
2. int summation(int[]);
3. void main ()
4. {
5. int arr[5] = {0,1,2,3,4};
6. int sum = summation(arr);
7. printf("%d",sum);
8. }
9. int summation (int arr[])
10. {
11. int sum=0,i;
12. for (i = 0; i<5; i++)
13. {
14. sum = sum + arr[i];
15. }
16. return sum;
17. }
The above program defines a function named as summation which accepts an array as an
argument. The function calculates the sum of all the elements of the array and returns it.
2D Array
2D array can be defined as an array of arrays. The 2D array is organized as matrices which
can be represented as the collection of rows and columns.
However, 2D arrays are created to implement a relational database look alike data structure.
It provides ease of holding bulk of data at once which can be passed to any number of
functions wherever required.
Above image shows the two dimensional array, the elements are organized in the form of
rows and columns. First element of the first row is represented by a[0][0] where the number
shown in the first index is the number of that row while the number shown in the second
index is the number of the column.
Due to the fact that the elements of 2D arrays can be random accessed. Similar to one
dimensional arrays, we can access the individual cells in a 2D array by using the indices of
the cells. There are two indices attached to a particular cell, one is its row number while the
other is its column number.
However, we can store the value stored in any particular cell of a 2D array to some variable x
by using the following syntax.
1. int x = a[i][j];
Where i and j is the row and column number of the cell respectively.
We can assign each cell of a 2D array to 0 by using the following code:
1. for ( int i=0; i<n ;i++)
2. {
3. for (int j=0; j<n; j++)
4. {
5. a[i][j] = 0;
6. }
7. }
Initializing 2D Arrays
We know that, when we declare and initialize one dimensional array in C programming
simultaneously, we don't need to specify the size of the array. However this will not work
with 2D arrays. We will have to define at least the second dimension of the array.
The number of elements that can be present in a 2D array will always be equal to (number of
rows * number of columns).
C Example :
1. #include <stdio.h>
2. void main ()
3. {
4. int arr[3][3],i,j;
5. for (i=0;i<3;i++)
6. {
7. for (j=0;j<3;j++)
8. {
9. printf("Enter a[%d][%d]: ",i,j);
10. scanf("%d",&arr[i][j]);
11. }
12. }
13. printf("\n printing the elements ....\n");
14. for(i=0;i<3;i++)
15. {
16. printf("\n");
17. for (j=0;j<3;j++)
18. {
19. printf("%d\t",arr[i][j]);
20. }
21. }
22. }
When it comes to map a 2 dimensional array, most of us might think that why this mapping is
required. However, 2 D arrays exists from the user point of view. 2D arrays are created to
implement a relational database table lookalike data structure, in computer memory, the
storage technique for 2D array is similar to that of an one dimensional array.
The size of a two dimensional array is equal to the multiplication of number of rows and the
number of columns present in the array. We do need to map two dimensional array to the one
dimensional array in order to store them in the memory.
A 3 X 3 two dimensional array is shown in the following image. However, this array needs to
be mapped to a one dimensional array in order to store it into the memory.
There are two main techniques of storing 2D array elements into memory
first, the 1st row of the array is stored into the memory completely, then the 2nd row of the
array is stored into the memory completely and so on till the last row.
2. Column major ordering
According to the column major ordering, all the columns of the 2D array are stored into the
memory contiguously. The memory allocation of the array which is shown in in the above
image is given as follows.
first, the 1st column of the array is stored into the memory completely, then the 2nd row of the
array is stored into the memory completely and so on till the last column of the array.
Address(a[i][j]) = ((j*m)+i)*Size + BA
where BA is the base address of the array.
Example:
1. A [5 ... +20][20 ... 70], BA = 1020, Size of element = 8 bytes.
2. Find the location of a[0][30].
3. Address [A[0][30]) = ((30-20) x 24 + 5) x 8 + 1020 = 245 x 8 + 1020 = 2980 bytes
Stack
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 a
card or plate from the top of the stack only. Likewise, Stack ADT allows all data operations
at one end only. At any given time, we can only access the top element of a stack.
This feature makes it LIFO data structure. LIFO stands for Last-in-first-out. Here, the
element which is placed (inserted or added) last, is accessed first. In stack terminology,
insertion operation is called PUSH operation and removal operation is called POP operation.
Stack Representation
The following diagram depicts a stack and its operations −
A stack can be implemented by means of Array, Structure, Pointer, and Linked List. Stack
can either be a fixed size one or it may have a sense of dynamic resizing. Here, we are going
to implement stack using arrays, which makes it a fixed size stack implementation.
Basic Operations
Stack operations may involve initializing the stack, using it and then de-initializing it. Apart
from these basic stuffs, a stack is used for the following two primary operations −
push() − Pushing (storing) an element on the stack.
pop() − Removing (accessing) an element from the stack.
When data is Pushed onto stack.
To use a stack efficiently, we need to check the status of stack as well. For the same purpose,
the following functionality is added to stacks –
peek() − get the top data element of the stack, without removing it.
isFull() − check if stack is full.
isEmpty() − check if stack is empty.
At all times, we maintain a pointer to the last PUSHed data on the stack. As this pointer
always represents the top of the stack, hence named top. The top pointer provides top value
of the stack without actually removing it.
isfull()
Algorithm of isfull() function –
end procedure
bool isfull() {
if(top == MAXSIZE)
return true;
else
return false;
}
isempty()
Algorithm of isempty() function –
end procedure
Implementation of isempty() function in C programming language 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.
Push Operation
The process of putting a new data element onto stack is known as a Push Operation. Push
operation involves a series of steps −
Step 1 − Checks if the stack is full.
Step 2 − If the stack is full, produces an error and exit.
Step 3 − If the stack is not full, increments top to point next empty space.
Step 4 − Adds data element to the stack location, where top is pointing.
Step 5 − Returns success.
If the linked list is used to implement the stack, then in step 3, we need to allocate space
dynamically.
Algorithm for PUSH Operation
A simple algorithm for Push operation can be derived as follows –
if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure
Pop Operation
Accessing the content while removing it from the stack, is known as a Pop Operation. In an
array implementation of pop() operation, the data element is not actually removed,
instead top is decremented to a lower position in the stack to point to the next value. But in
linked-list implementation, pop() actually removes data element and deallocates memory
space.
A Pop operation may involve the following steps −
Step 1 − Checks if the stack is empty.
Step 2 − If the stack is empty, produces an error and exit.
Step 3 − If the stack is not empty, accesses the data element at which top is pointing.
Step 4 − Decreases the value of top by 1.
Step 5 − Returns success.
if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
end procedure
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}
Queue
Queue is an abstract data structure, somewhat similar to Stacks. Unlike stacks, a queue is
open at both its ends. One end is always used to insert data (enqueue) and the other is used to
remove data (dequeue). Queue follows First-In-First-Out methodology, i.e., the data item
stored first will be accessed first.
A real-world example of queue can be a single-lane one-way road, where the vehicle enters
first, exits first. More real-world examples can be seen as queues at the ticket windows and
bus-stops.
Queue Representation
As we now understand that in queue, we access both ends for different reasons. The
following diagram given below tries to explain queue representation as data structure −
As in stacks, a queue can also be implemented using Arrays, Linked-lists, Pointers and
Structures. For the sake of simplicity, we shall implement queues using one-dimensional
array.
Basic Operations
Queue operations may involve initializing or defining the queue, utilizing it, and then
completely erasing it from the memory. Here we shall try to understand the basic operations
associated with queues –
Few more functions are required to make the above-mentioned queue operation efficient.
These are −
peek() − Gets the element at the front of the queue without removing it.
isfull() − Checks if the queue is full.
isempty() − Checks if the queue is empty.
In queue, we always dequeue (or access) data, pointed by front pointer and while enqueing
(or storing) data in the queue we take help of rear pointer.
Algorithm
begin procedure peek
return queue[front]
end procedure
Example
int peek() {
return queue[front];
}
isfull()
As we are using single dimension array to implement queue, we just check for the rear
pointer to reach at MAXSIZE to determine that the queue is full. In case we maintain the
queue in a circular linked-list, the algorithm will differ.
Algorithm of isfull() function −
Algorithm
begin procedure isfull
end procedure
isempty()
Algorithm of isempty() function –
Algorithm
begin procedure isempty
end procedure
If the value of front is less than MIN or 0, it tells that the queue is not yet initialized, hence
empty.
Enqueue Operation
Queues maintain two data pointers, front and rear. Therefore, its operations are
comparatively difficult to implement than that of stacks.
The following steps should be taken to enqueue (insert) data into a queue −
Step 1 − Check if the queue is full.
Step 2 − If the queue is full, produce overflow error and exit.
Step 3 − If the queue is not full, increment rear pointer to point the next empty space.
Step 4 − Add data element to the queue location, where the rear is pointing.
Step 5 − return success.
Sometimes, we also check to see if a queue is initialized or not, to handle any unforeseen
situations.
Algorithm for enqueue operation
procedure enqueue(data)
if queue is full
return overflow
endif
rear ← rear + 1
queue[rear] ← data
return true
end procedure
rear = rear + 1;
queue[rear] = data;
return 1;
end procedure
Dequeue Operation
Accessing data from the queue is a process of two tasks − access the data where front is
pointing and remove the data after access. The following steps are taken to
perform dequeue operation −
Step 1 − Check if the queue is empty.
Step 2 − If the queue is empty, produce underflow error and exit.
Step 3 − If the queue is not empty, access the data where front is pointing.
Step 4 − Increment front pointer to point to the next available data element.
Step 5 − Return success.
data = queue[front]
front ← front + 1
return true
end procedure
return data;
}
Stack is overflown when we try to insert an element into a completely filled stack therefore,
our main function must always avoid stack overflow condition.
Algorithm:
1. begin
2. if top = n then stack full
3. top = top + 1
4. stack (top) : = item;
5. end
Deletion of an element from the top of the stack is called pop operation. The value of the
variable top will be incremented by 1 whenever an item is deleted from the stack. The top
most element of the stack is stored in a variable and then the top is decremented by 1. The
operation returns the deleted value that was stored in another variable as the result.
The underflow condition occurs when we try to delete an element from an already empty
stack.
Algorithm :
1. begin
2. if top = 0 then stack empty;
3. item := stack(top);
4. top = top - 1;
5. end;
Time Complexity : o(1)
Implementation of POP algorithm using C language
1. int pop ()
2. {
3. if(top == -1)
4. {
5. printf("Underflow");
6. return 0;
7. }
8. else
9. {
10. return stack[top - - ];
11. }
12. }
Algorithm:
PEEK (STACK, TOP)
1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End
Time complexity: o (n)
C program
1. #include <stdio.h>
2. int stack[100],i,j,choice=0,n,top=-1;
3. void push();
4. void pop();
5. void show();
6. void main ()
7. {
8. printf("Enter the number of elements in the stack ");
9. scanf("%d",&n);
10. printf("*********Stack operations using array*********");
11. printf("\n----------------------------------------------\n");
12. while(choice != 4)
13. {
14. printf("Chose one from the below options...\n");
15. printf("\n1.Push\n2.Pop\n3.Show\n4.Exit");
16. printf("\n Enter your choice \n");
17. scanf("%d",&choice);
18. switch(choice)
19. {
20. case 1:
21. {
22. push();
23. break;
24. }
25. case 2:
26. {
27. pop();
28. break;
29. }
30. case 3:
31. {
32. show();
33. break;
34. }
35. case 4:
36. {
37. printf("Exiting....");
38. break;
39. }
40. default:
41. {
42. printf("Please Enter valid choice ");
43. }
44. };
45. }
46. }
47.
48. void push ()
49. {
50. int val;
51. if (top == n )
52. printf("\n Overflow");
53. else
54. {
55. printf("Enter the value?");
56. scanf("%d",&val);
57. top = top +1;
58. stack[top] = val;
59. }
60. }
61. void pop ()
62. {
63. if(top == -1)
64. printf("Underflow");
65. else
66. top = top -1;
67. }
68. void show()
69. {
70. for (i=top;i>=0;i--)
71. {
72. printf("%d\n",stack[i]);
73. }
74. if(top == -1)
75. {
76. printf("Stack is empty");
77. }
78. }
Instead of using array, we can also use linked list to implement stack. Linked list allocates the
memory dynamically. However, time complexity in both the scenario is same for all the
operations i.e. push, pop and peek.
In linked list implementation of stack, the nodes are maintained non-contiguously in the
memory. Each node contains a pointer to its immediate successor node in the stack. Stack is
said to be overflown if the space left in the memory heap is not enough to create a node.
The top most node in the stack always contains null in its address field. Let’s discuss the way
in which, each operation is performed in linked list implementation of stack.
Adding a node to the stack is referred to as push operation. Pushing an element to a stack in
linked list implementation is different from that of an array implementation. In order to push
an element onto the stack, the following steps are involved.
C implementation:
1. void push ()
2. {
3. int val;
4. struct node *ptr =(struct node*)malloc(sizeof(struct node));
5. if(ptr == NULL)
6. {
7. printf("not able to push the element");
8. }
9. else
10. {
11. printf("Enter the value");
12. scanf("%d",&val);
13. if(head==NULL)
14. {
15. ptr->val = val;
16. ptr -> next = NULL;
17. head=ptr;
18. }
19. else
20. {
21. ptr->val = val;
22. ptr->next = head;
23. head=ptr;
24. }
25. printf("Item pushed");
26. }
27. }
1. Check for the underflow condition: The underflow condition occurs when
we try to pop from an already empty stack. The stack will be empty if the head pointer of the
list points to null.
2. Adjust the head pointer accordingly: In stack, the elements are popped only from one end,
therefore, the value stored in the head pointer must be deleted and the node must be freed.
The next node of the head node now becomes the head node.
C implementation
1. void pop()
2. {
3. int item;
4. struct node *ptr;
5. if (head == NULL)
6. {
7. printf("Underflow");
8. }
9. else
10. {
11. item = head->val;
12. ptr = head;
13. head = head->next;
14. free(ptr);
15. printf("Item popped");
16. }
17. }
C Implementation
1. void display()
2. {
3. int i;
4. struct node *ptr;
5. ptr=head;
6. if(ptr == NULL)
7. {
8. printf("Stack is empty\n");
9. }
10. else
11. {
12. printf("Printing Stack elements \n");
13. while(ptr!=NULL)
14. {
15. printf("%d\n",ptr->val);
16. ptr = ptr->next;
17. }
18. }
19. }
Queue
1. A queue can be defined as an ordered list which enables insert operations to be performed
at one end called REAR and delete operations to be performed at another end
called FRONT.
2. Queue is referred to be as First In First Out list.
3. For example, people waiting in line for a rail ticket form a queue.
Applications of Queue
1. Queues are widely used as waiting lists for a single shared resource like printer, disk, CPU.
2. Queues are used in asynchronous transfer of data (where data is not being transferred at the
same rate between two processes) for eg. Pipes, file IO, sockets.
3. Queues are used as buffers in most of the applications like MP3 media player, CD player, etc.
4. Queue are used to maintain the play list in media players in order to add and remove the
songs from the play-list.
5. Queues are used in operating systems for handling interrupts.
Complexity
Data Time Complexity Space
Struct Comple
ure ity
Queue θ(n) θ(n) θ(1) θ(1) O(n) O(n) O(1) O(1) O(n)
Types of Queues
What is the Queue?
A queue in the data structure can be considered similar to the queue in the real-world. A
queue is a data structure in which whatever comes first will go out first. It follows the FIFO
(First-In-First-Out) policy.
In Queue, the insertion is done from one end known as the rear end or the tail of the queue,
whereas the deletion is done from another end known as the front end or the head of the
queue. In other words, it can be defined as a list or a collection with a constraint that the
insertion can be performed at one end called as the rear end or tail of the queue and deletion
is performed on another end called as the front end or the head of the queue.
Operations on Queue
There are two fundamental operations performed on a Queue:
o Enqueue: The enqueue operation is used to insert the element at the rear end of the queue. It
returns void.
o Dequeue: The dequeue operation performs the deletion from the front-end of the queue. It
also returns the element which has been removed from the front-end. It returns an integer
value. The dequeue operation can also be designed to void.
o Peek: This is the third operation that returns the element, which is pointed by the front
pointer in the queue but does not delete it.
o Queue overflow (isfull): When the Queue is completely full, then it shows the overflow
condition.
o Queue underflow (isempty): When the Queue is empty, i.e., no elements are in the Queue
then it throws the underflow condition.
Implementation of Queue
There are two ways of implementing the Queue:
o Sequential allocation: The sequential allocation in a Queue can be implemented using an
array.
For more details, click on the below link: https://www.javatpoint.com/array-representation-
of-queue
o Linked list allocation: The linked list allocation in a Queue can be implemented using a
linked list.
Types of Queue
There are four types of Queues:
o Linear Queue
In Linear Queue, an insertion takes place from one end while the deletion occurs from
another end. The end at which the insertion takes place is known as the rear end, and the end
at which the deletion takes place is known as front end. It strictly follows the FIFO rule. The
linear Queue can be represented, as shown in the below figure:
The above figure shows that the elements are inserted from the rear end, and if we insert
more elements in a Queue, then the rear value gets incremented on every insertion. If we
want to show the deletion, then it can be represented as:
In the above figure, we can observe that the front pointer points to the next element, and the
element which was previously pointed by the front pointer was deleted.
The major drawback of using a linear Queue is that insertion is done only from the rear end.
If the first three elements are deleted from the Queue, we cannot insert more elements even
though the space is available in a Linear Queue. In this case, the linear Queue shows
the overflow condition as the rear is pointing to the last element of the Queue.
o Circular Queue
In Circular Queue, all the nodes are represented as circular. It is similar to the linear Queue
except that the last element of the queue is connected to the first element. It is also known
as Ring Buffer as all the ends are connected to another end. The circular queue can be
represented as:
The drawback that occurs in a linear queue is overcome by using the circular queue. If the
empty space is available in a circular queue, the new element can be added in an empty space
by simply incrementing the value of rear.
o Priority Queue
A priority queue is another special type of Queue data structure in which each element has
some priority associated with it. Based on the priority of the element, the elements are
arranged in a priority queue. If the elements occur with the same priority, then they are served
according to the FIFO principle.
In priority Queue, the insertion takes place based on the arrival while the deletion occurs
based on the priority. The priority Queue can be shown as:
The above figure shows that the highest priority element comes first and the elements of the
same priority are arranged based on FIFO structure.
o Deque
Both the Linear Queue and Deque are different as the linear queue follows the FIFO principle
whereas, deque does not follow the FIFO principle. In Deque, the insertion and deletion can
occur from both ends.
The above figure shows the queue of characters forming the English word "HELLO". Since,
No deletion is performed in the queue till now, therefore the value of front remains -1 .
However, the value of rear increases by one every time an insertion is performed in the
queue. After inserting an element into the queue shown in the above figure, the queue will
look something like following. The value of rear will become 5 while the value of front
remains same.
After deleting an element, the value of front will increase from -1 to 0. however, the queue
will look something like following.
If the item is to be inserted as the first element in the list, in that case set the value of front
and rear to 0 and insert the element at the rear end.
Otherwise keep increasing the value of rear and insert each element one by one having rear as
the index.
Algorithm
o Step 1: IF REAR = MAX - 1
Write OVERFLOW
Go to step
[END OF IF]
o Step 2: IF FRONT = -1 and REAR = -1
SET FRONT = REAR = 0
ELSE
SET REAR = REAR + 1
[END OF IF]
o Step 3: Set QUEUE[REAR] = NUM
o Step 4: EXIT
C Function
1. void insert (int queue[], int max, int front, int rear, int item)
2. {
3. if (rear + 1 == max)
4. {
5. printf("overflow");
6. }
7. else
8. {
9. if(front == -1 && rear == -1)
10. {
11. front = 0;
12. rear = 0;
13. }
14. else
15. {
16. rear = rear + 1;
17. }
18. queue[rear]=item;
19. }
20. }
Otherwise, keep increasing the value of front and return the item stored at the front end of the
queue at each time.
Algorithm
o Step 1: IF FRONT = -1 or FRONT > REAR
Write UNDERFLOW
ELSE
SET VAL = QUEUE[FRONT]
SET FRONT = FRONT + 1
[END OF IF]
o Step 2: EXIT
C Function
1. int delete (int queue[], int max, int front, int rear)
2. {
3. int y;
4. if (front == -1 || front > rear)
5. {
6. printf("underflow");
7. }
8. else
9. {
10. y = queue[front];
11. if(front == rear)
12. {
13. front = rear = -1;
14. else
15. front = front + 1;
16. }
17. return y;
18. }
19. }
o Memory wastage: The space of the array, which is used to store queue elements, can never
be reused to store the elements of that queue because the elements can only be inserted at
front end and the value of front might be so high so that, all the space before that, can never
be filled.
The above figure shows how the memory space is wasted in the array representation of
queue. In the above figure, a queue of size 10 having 3 elements, is shown. The value of the
front variable is 5, therefore, we cannot reinsert the values in the place of already deleted
element before the position of front. That much space of the array is wasted and cannot be
used in the future (for this queue).
The storage requirement of linked representation of a queue with n elements is o(n) while the
time requirement for operations is o(1).
In a linked queue, each node of the queue consists of two parts i.e. data part and the link part.
Each element of the queue points to its immediate next element in the memory.
In the linked queue, there are two pointers maintained in the memory i.e. front pointer and
rear pointer. The front pointer contains the address of the starting element of the queue while
the rear pointer contains the address of the last element of the queue.
Insertion and deletions are performed at rear and front end respectively. If front and rear both
are NULL, it indicates that the queue is empty.
The linked representation of queue is shown in the following figure.
Firstly, allocate the memory for the new node ptr by using the following statement.
There can be the two scenario of inserting this new node ptr into the linked queue.
In the first scenario, we insert element into an empty queue. In this case, the condition front
= NULL becomes true. Now, the new element will be added as the only element of the queue
and the next pointer of front and rear pointer both, will point to NULL.
In the second case, the queue contains more than one element. The condition front = NULL
becomes false. In this scenario, we need to update the end pointer rear so that the next pointer
of rear will point to the new node ptr. Since, this is a linked queue, hence we also need to
make the rear pointer point to the newly added node ptr. We also need to make the next
pointer of rear point to NULL.
Algorithm
o Step 1: Allocate the space for the new node PTR
o Step 2: SET PTR -> DATA = VAL
o Step 3: IF FRONT = NULL
SET FRONT = REAR = PTR
SET FRONT -> NEXT = REAR -> NEXT = NULL
ELSE
SET REAR -> NEXT = PTR
SET REAR = PTR
SET REAR -> NEXT = NULL
[END OF IF]
o Step 4: END
C Function
1. void insert(struct node *ptr, int item; )
2. {
3. ptr = (struct node *) malloc (sizeof(struct node));
4. if(ptr == NULL)
5. {
6. printf("\nOVERFLOW\n");
7. return;
8. }
9. else
10. {
11. ptr -> data = item;
12. if(front == NULL)
13. {
14. front = ptr;
15. rear = ptr;
16. front -> next = NULL;
17. rear -> next = NULL;
18. }
19. else
20. {
21. rear -> next = ptr;
22. rear = ptr;
23. rear->next = NULL;
24. }
25. }
26. }
Deletion
Deletion operation removes the element that is first inserted among all the queue elements.
Firstly, we need to check either the list is empty or not. The condition front == NULL
becomes true if the list is empty, in this case , we simply write underflow on the console and
make exit.
Otherwise, we will delete the element that is pointed by the pointer front. For this purpose,
copy the node pointed by the front pointer into the pointer ptr. Now, shift the front pointer,
point to its next node and free the node pointed by the node ptr. This is done by using the
following statements.
1. ptr = front;
2. front = front -> next;
3. free(ptr);
C Function
1. void delete (struct node *ptr)
2. {
3. if(front == NULL)
4. {
5. printf("\nUNDERFLOW\n");
6. return;
7. }
8. else
9. {
10. ptr = front;
11. front = front -> next;
12. free(ptr);
13. }
14. }
Circular Queue
Why was the concept of the circular queue introduced?
There was one limitation in the array implementation of Queue. If the rear reaches to the end
position of the Queue then there might be possibility that some vacant spaces are left in the
beginning which cannot be utilized. So, to overcome such limitations, the concept of the
circular queue was introduced.
As we can see in the above image, the rear is at the last position of the Queue and front is
pointing somewhere rather than the 0th position. In the above array, there are only two
elements and other three positions are empty. The rear is at the last position of the Queue; if
we try to insert the element then it will show that there are no empty spaces in the Queue.
There is one solution to avoid such wastage of memory space by shifting both the elements at
the left and adjust the front and rear end accordingly. It is not a practically good approach
because shifting all the elements will consume lots of time. The efficient approach to avoid
the wastage of the memory is to use the circular queue data structure.
The following are the operations that can be performed on a circular queue:
o Front: It is used to get the front element from the Queue.
o Rear: It is used to get the rear element from the Queue.
o enQueue(value): This function is used to insert the new value in the Queue. The new
element is always inserted from the rear end.
o deQueue(): This function deletes an element from the Queue. The deletion in a Queue
always takes place from the front end.
Enqueue operation
The steps of enqueue operation are given below:
Dequeue Operation
The steps of dequeue operation are given below:
o First, we check whether the Queue is empty or not. If the queue is empty, we cannot perform
the dequeue operation.
o When the element is deleted, the value of front gets decremented by 1.
o If there is only one element left which is to be deleted, then the front and rear are reset to -1.
Let's understand the enqueue and dequeue operation through the diagrammatic
representation.
Implementation of circular queue using Array
1. #include <stdio.h>
2. # define max 6
3. int queue[max]; // array declaration
4. int front=-1;
5. int rear=-1;
6. // function to insert an element in a circular queue
7. void enqueue(int element)
8. {
9. if(front==-1 && rear==-1) // condition to check queue is empty
10. {
11. front=0;
12. rear=0;
13. queue[rear]=element;
14. }
15. else if((rear+1)%max==front) // condition to check queue is full
16. {
17. printf("Queue is overflow..");
18. }
19. else
20. {
21. rear=(rear+1)%max; // rear is incremented
22. queue[rear]=element; // assigning a value to the queue at the rear position.
23. }
24. }
25. // function to delete the element from the queue
26. int dequeue()
27. {
28. if((front==-1) && (rear==-1)) // condition to check queue is empty
29. {
30. printf("\nQueue is underflow..");
31. }
32. else if(front==rear)
33. {
34. printf("\nThe dequeued element is %d", queue[front]);
35. front=-1;
36. rear=-1;
37. }
38. else
39. {
40. printf("\nThe dequeued element is %d", queue[front]);
41. front=(front+1)%max;
42. }
43. }
44. // function to display the elements of a queue
45. void display()
46. {
47. int i=front;
48. if(front==-1 && rear==-1)
49. {
50. printf("\n Queue is empty..");
51. }
52. else
53. {
54. printf("\nElements in a Queue are :");
55. while(i<=rear)
56. {
57. printf("%d,", queue[i]);
58. i=(i+1)%max;
59. }
60. }
61. }
62. int main()
63. {
64. int choice=1,x; // variables declaration
65. while(choice<4 && choice!=0) // while loop
66. {
67. printf("\n Press 1: Insert an element");
68. printf("\nPress 2: Delete an element");
69. printf("\nPress 3: Display the element");
70. printf("\nEnter your choice");
71. scanf("%d", &choice);
72. switch(choice)
73. {
74. case 1:
75. printf("Enter the element which is to be inserted");
76. scanf("%d", &x);
77. enqueue(x);
78. break;
79. case 2:
80. dequeue();
81. break;
82. case 3:
83. display();
84. }}
85. return 0;
86. }
As we know that linked list is a linear data structure that stores two parts, i.e., data part and
the address part where address part contains the address of the next node. Here, linked list is
used to implement the circular queue; therefore, the linked list follows the properties of the
Queue. When we are implementing the circular queue using linked list then both the enqueue
and dequeue operations take O(1) time.
1. #include <stdio.h>
2. // Declaration of struct type node
3. struct node
4. {
5. int data;
6. struct node *next;
7. };
8. struct node *front=-1;
9. struct node *rear=-1;
10. // function to insert the element in the Queue
11. void enqueue(int x)
12. {
13. struct node *newnode; // declaration of pointer of struct node type.
14. newnode=(struct node *)malloc(sizeof(struct node)); // allocating the memory to the new
node
15. newnode->data=x;
16. newnode->next=0;
17. if(rear==-1) // checking whether the Queue is empty or not.
18. {
19. front=rear=newnode;
20. rear->next=front;
21. }
22. else
23. {
24. rear->next=newnode;
25. rear=newnode;
26. rear->next=front;
27. }
28. }
29. // function to delete the element from the queue
30. void dequeue()
31. {
32. struct node *temp; // declaration of pointer of node type
33. temp=front;
34. if((front==-1)&&(rear==-1)) // checking whether the queue is empty or not
35. {
36. printf("\nQueue is empty");
37. }
38. else if(front==rear) // checking whether the single element is left in the queue
39. {
40. front=rear=-1;
41. free(temp);
42. }
43. else
44. {
45. front=front->next;
46. rear->next=front;
47. free(temp);
48. }
49. }
50. // function to get the front of the queue
51. int peek()
52. {
53. if((front==-1) &&(rear==-1))
54. {
55. printf("\nQueue is empty");
56. }
57. else
58. {
59. printf("\nThe front element is %d", front->data);
60. }
61. }
62. // function to display all the elements of the queue
63. void display()
64. {
65. struct node *temp;
66. temp=front;
67. printf("\n The elements in a Queue are : ");
68. if((front==-1) && (rear==-1))
69. {
70. printf("Queue is empty");
71. }
72. else
73. {
74. while(temp->next!=front)
75. {
76. printf("%d,", temp->data);
77. temp=temp->next;
78. }
79. printf("%d", temp->data);
80. }
81. }
82. void main()
83. {
84. enqueue(34);
85. enqueue(10);
86. enqueue(23);
87. display();
88. dequeue();
89. peek();
90. }
Dequeue
The dequeue stands for Double Ended Queue. In the queue, the insertion takes place from
one end while the deletion takes place from another end. The end at which the insertion
occurs is known as the rear end whereas the end at which the deletion occurs is known
as front end.
Deque is a linear data structure in which the insertion and deletion operations are performed
from both ends. We can say that deque is a generalized version of the queue.
In deque, the insertion and deletion operation can be performed from one side. The stack
follows the LIFO rule in which both the insertion and deletion can be performed only from
one end; therefore, we conclude that deque can be considered as a stack.
In deque, the insertion can be performed on one end, and the deletion can be done on another
end. The queue follows the FIFO rule in which the element is inserted on one end and deleted
from another end. Therefore, we conclude that the deque can also be considered as the queue.
There are two types of Queues, Input-restricted queue, and output-restricted queue.
1. Input-restricted queue: The input-restricted queue means that some restrictions are applied
to the insertion. In input-restricted queue, the insertion is applied to one end while the
deletion is applied from both the ends.
2. Output-restricted queue: The output-restricted queue means that some restrictions are
applied to the deletion operation. In an output-restricted queue, the deletion can be applied
only from one end, whereas the insertion is possible from both ends.
Operations on Dequeue
Memory Representation
The deque can be implemented using two data structures, i.e., circular array, and doubly
linked list. To implement the deque using circular array, we first should know what circular
array is.
Applications of Dequeue
o The deque can be used as a stack and queue; therefore, it can perform both redo and undo
operations.
o It can be used as a palindrome checker means that if we read the string from both ends, then
the string would be the same.
o It can be used for multiprocessor scheduling. Suppose we have two processors, and each
processor has one process to execute. Each processor is assigned with a process or a job, and
each process contains multiple threads. Each processor maintains a deque that contains
threads that are ready to execute. The processor executes a process, and if a process creates a
child process then that process will be inserted at the front of the deque of the parent process.
o Suppose the processor P2 has completed the execution of all its threads then it steals the
thread from the rear end of the processor P1 and adds to the front end of the processor P2. The
processor P2 will take the thread from the front end; therefore, the deletion takes from both
the ends, i.e., front and rear end. This is known as the A-steal algorithm for scheduling.
3. Suppose we want to insert the next element from the rear. To insert the element from the rear
end, we first need to increment the rear, i.e., rear=rear+1. Now, the rear is pointing to the
second element, and the front is pointing to the first element.
4. Suppose we are again inserting the element from the rear end. To insert the element, we will
first increment the rear, and now rear points to the third element.
5. If we want to insert the element from the front end, and insert an element from the front, we
have to decrement the value of front by 1. If we decrement the front by 1, then the front
points to -1 location, which is not any valid location in an array. So, we set the front as (n -
1), which is equal to 4 as n is 5. Once the front is set, we will insert the value as shown in the
below figure:
Dequeue Operation
1. If the front is pointing to the last element of the array, and we want to perform the delete
operation from the front. To delete any element from the front, we need to set front=front+1.
Currently, the value of the front is equal to 4, and if we increment the value of front, it
becomes 5 which is not a valid index. Therefore, we conclude that if front points to the last
element, then front is set to 0 in case of delete operation.
2. If we want to delete the element from rear end then we need to decrement the rear value by 1,
i.e., rear=rear-1 as shown in the below figure:
3. If the rear is pointing to the first element, and we want to delete the element from the rear end
then we have to set rear=n-1 where n is the size of the array as shown in the below figure:
1. #define size 5
2. #include <stdio.h>
3. int deque[size];
4. int f=-1, r=-1;
5. // enqueue_front function will insert the value from the front
6. void enqueue_front(int x)
7. {
8. if((f==0 && r==size-1) || (f==r+1))
9. {
10. printf("deque is full");
11. }
12. else if((f==-1) && (r==-1))
13. {
14. f=r=0;
15. deque[f]=x;
16. }
17. else if(f==0)
18. {
19. f=size-1;
20. deque[f]=x;
21. }
22. else
23. {
24. f=f-1;
25. deque[f]=x;
26. }
27. }
28. // enqueue_rear function will insert the value from the rear
29. void enqueue_rear(int x)
30. {
31. if((f==0 && r==size-1) || (f==r+1))
32. {
33. printf("deque is full");
34. }
35. else if((f==-1) && (r==-1))
36. {
37. r=0;
38. deque[r]=x;
39. }
40. else if(r==size-1)
41. {
42. r=0;
43. deque[r]=x;
44. }
45. else
46. {
47. r++;
48. deque[r]=x;
49. }
50. }
51. // display function prints all the value of deque.
52. void display()
53. {
54. int i=f;
55. printf("\n Elements in a deque : ");
56. while(i!=r)
57. {
58. printf("%d ",deque[i]);
59. i=(i+1)%size;
60. }
61. printf("%d",deque[r]);
62. }
63. // getfront function retrieves the first value of the deque.
64. void getfront()
65. {
66. if((f==-1) && (r==-1))
67. {
68. printf("Deque is empty");
69. }
70. else
71. {
72. printf("\nThe value of the front is: %d", deque[f]);
73. }
74. }
75. // getrear function retrieves the last value of the deque.
76. void getrear()
77. {
78. if((f==-1) && (r==-1))
79. {
80. printf("Deque is empty");
81. }
82. else
83. {
84. printf("\nThe value of the rear is: %d", deque[r]);
85. }
86. }
87. // dequeue_front() function deletes the element from the front
88. void dequeue_front()
89. {
90. if((f==-1) && (r==-1))
91. {
92. printf("Deque is empty");
93. }
94. else if(f==r)
95. {
96. printf("\nThe deleted element is %d", deque[f]);
97. f=-1;
98. r=-1;
99. }
100. else if(f==(size-1))
101. {
102. printf("\nThe deleted element is %d", deque[f]);
103. f=0;
104. }
105. else
106. {
107. printf("\nThe deleted element is %d", deque[f]);
108. f=f+1;
109. }
110. }
111. // dequeue_rear() function deletes the element from the rear
112. void dequeue_rear()
113. {
114. if((f==-1) && (r==-1))
115. {
116. printf("Deque is empty");
117. }
118. else if(f==r)
119. {
120. printf("\nThe deleted element is %d", deque[r]);
121. f=-1;
122. r=-1;
123. }
124. else if(r==0)
125. {
126. printf("\nThe deleted element is %d", deque[r]);
127. r=size-1;
128. }
129. else
130. {
131. printf("\nThe deleted element is %d", deque[r]);
132. r=r-1;
133. }
134. }
135. int main()
136. {
137. // inserting a value from the front.
138. enqueue_front(2);
139. // inserting a value from the front.
140. enqueue_front(1);
141. // inserting a value from the rear.
142. enqueue_rear(3);
143. // inserting a value from the rear.
144. enqueue_rear(5);
145. // inserting a value from the rear.
146. enqueue_rear(8);
147. // Calling the display function to retrieve the values of deque
148. display();
149. // Retrieve the front value
150. getfront();
151. // Retrieve the rear value.
152. getrear();
153. // deleting a value from the front
154. dequeue_front();
155. //deleting a value from the rear
156. dequeue_rear();
157. // Calling the display function to retrieve the values of deque
158. display();
159. return 0;
160. }
The priority queue supports only comparable elements, which means that the elements are
either arranged in an ascending or descending order.
For example, suppose we have some values like 1, 3, 4, 8, 14, 22 inserted in a priority queue
with an ordering imposed on the values is from least to the greatest. Therefore, the 1 number
would be having the highest priority while 22 will be having the lowest priority.
All the values are arranged in ascending order. Now, we will observe how the priority queue
will look after performing the following operations:
o poll(): This function will remove the highest priority element from the priority queue. In the
above priority queue, the '1' element has the highest priority, so it will be removed from the
priority queue.
o add(2): This function will insert '2' element in a priority queue. As 2 is the smallest element
among all the numbers so it will obtain the highest priority.
o poll(): It will remove '2' element from the priority queue as it has the highest priority queue.
o add(5): It will insert 5 element after 4 as 5 is larger than 4 and lesser than 8, so it will obtain
the third highest priority in a priority queue.
Types of Priority Queue
o Descending order priority queue: In descending order priority queue, a higher priority
number is given as a higher priority in a priority. For example, we take the numbers from 1 to
5 arranged in descending order like 5, 4, 3, 2, 1; therefore, the largest number, i.e., 5 is given
as the highest priority in a priority queue.
We will create the priority queue by using the list given below in which INFO list contains
the data elements, PRN list contains the priority numbers of each data element available in
the INFO list, and LINK basically contains the address of the next node.
Let's create the priority queue step by step.
In the case of priority queue, lower priority number is considered the higher priority,
Step 1: In the list, lower priority number is 1, whose data value is 333, so it will be inserted
in the list as shown in the below diagram:
Step 2: After inserting 333, priority number 2 is having a higher priority, and data values
associated with this priority are 222 and 111. So, this data will be inserted based on the FIFO
principle; therefore 222 will be added first and then 111.
Step 3: After inserting the elements of priority 2, the next higher priority number is 4 and
data elements associated with 4 priority numbers are 444, 555, 777. In this case, elements
would be inserted based on the FIFO principle; therefore, 444 will be added first, then 555,
and then 777.
Step 4: After inserting the elements of priority 4, the next higher priority number is 5, and the
value associated with priority 5 is 666, so it will be inserted at the end of the queue.
Implementation of Priority Queue
The priority queue can be implemented in four ways that include arrays, linked list, heap data
structure and binary search tree. The heap data structure is the most efficient way of
implementing the priority queue, so we will implement the priority queue using a heap data
structure in this topic. Now, first we understand the reason why heap is the most efficient way
among all the other data structures.
What is Heap?
A heap is a tree-based data structure that forms a complete binary tree, and satisfies the heap
property. If A is a parent node of B, then A is ordered with respect to the node B for all nodes
A and B in a heap. It means that the value of the parent node could be more than or equal to
the value of the child node, or the value of the parent node could be less than or equal to the
value of the child node. Therefore, we can say that there are two types of heaps:
o Max heap: The max heap is a heap in which the value of the parent node is greater than the
value of the child nodes.
o Min heap: The min heap is a heap in which the value of the parent node is less than the value
of the child nodes.
Both the heaps are the binary heap, as each has exactly two child nodes.
Priority Queue Operations
The common operations that we can perform on a priority queue are insertion, deletion and
peek. Let's see how we can maintain the heap data structure.
If the element is not in a correct place then it is compared with the parent node; if it is found
out of order, elements are swapped. This process continues until the element is placed in a
correct position.
o Removing the minimum element from the priority queue
As we know that in a max heap, the maximum element is the root node. When we remove the
root node, it creates an empty slot. The last inserted element will be added in this empty slot.
Then, this element is compared with the child nodes, i.e., left-child and right child, and swap
with the smaller of the two. It keeps moving down the tree until the heap property is restored.
Evaluation of Expression
There are 3 different ways to write an algebraic expressions:
Infix form
Prefix form
Postfix form
Infix form
Is exactly the fully parenthesized notation we have just introduced. Let me remind you once
again the Recursive definition
infix-expression := (infix-expression operand infix-expression)
infix-expression := atom
Examples
(3 * 7)
((1 + 3) * 2)
((1 + 3) * ( 2 - 3))
Main Feature:
the binary operator is between the two operands.
Question: what if we do not put all the parentheses? Then there are ambiguities on how to
interpret an expression: is 1+2*3 the same as (1+2)*3 or the same as 1+(2*3)? The
precedence of operators solves this problem.
Prefix form
Main Feature:
the operator preceeds the two operands.
Recursive definition of fully parenthesized version:
prefix-expression := (operand prefix-expression prefix-expression)
prefix-expression := atom
Recursive definition of classic version, without parentheses (we do not need them, because
there is no longer any ambiguity on how to match the operands to the operators):
prefix-expression := operand prefix-expression prefix-expression
prefix-expression := atom
Examples
(* 3 7) or simply * 3 7
(* ( + 1 3) 2) or simply * + 1 3 2
( * ( + 1 3) ( - 2 3)) or simply * + 1 3 - 2 3
Postfix form
Main Feature:
the operator is after the two operands. Recursive definition
postfix-expression := (operand postfix-expression postfix-expression)
postfix-expression := atom
Recursive definition of classic version, without parentheses (we do not need them, because
there is no longer any ambiguity on how to match the operands to the operators):
postfix-expression := operand postfix-expression postfix-expression
postfix-expression := atom
Examples
(3 7 *) or simply 3 7 *
((1 3 + ) 2 *) or simply 1 3 + 2 *
((1 3 +) ( 2 3 -) * ) or simply 1 3 + 2 3 - *
Associativity
Associativity describes the rule where operators with the same precedence appear in an
expression. For example, in the expression a + b − c, both + and – have the same precedence,
then which part of the expression will be evaluated first, is determined by associativity of
those operators. Here, both + and − are left associative, so the expression will be evaluated
as (a + b) − c.
The above table shows the default behavior of operators. At any point of time in expression
evaluation, the order can be altered by using parenthesis.
For example −
In a + b*c, the expression part b*c will be evaluated first, with multiplication as precedence
over addition. We here use parenthesis for a + b to be evaluated first, like (a + b)*c.
Why?
Why use PREFIX and POSTFIX notations when we have simple INFIX notation? INFIX
notations are not as simple as they seem especially while evaluating them. To evaluate an
infix expression we need to consider Operators’ Priority and Associative property
To solve this problem Precedence or Priority of the operators was defined. Operator
precedence governs the evaluation order. An operator with higher precedence is applied
before an operator with lower precedence.
The following table briefly tries to show the difference in all three notations −
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
6 ((a + b) ∗ c) - d -∗+abcd ab+c∗d-
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
To convert any
Infix expression into Postfix
or Prefix expression we can
use the
following procedure...
1. Find all the operators in the
given Infix
Expression.
2. Find the order of
operators
evaluated according to
their Operator
precedence.
3. Convert each operator into required type of expression (Postfix or Prefix) in the same order.
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*+ =
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-*
Procedure for
Postfix
Conversion
1. Scan the Infix string from left to right.
2. Initialize an empty stack.
3. If the scanned character is an operand, add it to the Postfix string.
4. If the scanned character is an operator and if the stack is empty push the character to stack.
If the scanned character is an Operator and the stack is not empty, compare the precedence
5.
of the character with the element on top of the stack.
If top Stack has higher precedence over the scanned character pop the stack else push the
6. scanned character to stack. Repeat this step until the stack is not empty and top Stack has
precedence over the character.
7. Repeat 4 and 5 steps till all the characters are scanned.
After all characters are scanned, we have to add any character that the stack may have to
8.
the Postfix string.
9. If stack is not empty add top Stack to Postfix string and Pop the stack.
10
Repeat this step as long as stack is not empty.
.
Conversion To Postfix
EXAMPLE:
A+(B*C-(D/E-F)*G)*H
Stack Input Output
Empty A+(B*C-(D/E-F)*G)*H -
Empty +(B*C-(D/E-F)*G)*H A
+ (B*C-(D/E-F)*G)*H A
+( B*C-(D/E-F)*G)*H A
+( *C-(D/E-F)*G)*H AB
+(* C-(D/E-F)*G)*H AB
+ *H ABC*DE/F-G*-
+* H ABC*DE/F-G*-
+* End ABC*DE/F-G*-H
Expression = (A+B^C)*D+E^5
5^E+D*)C^B+A(
5^E+D*(C^B+A)
E+D*(C^B+A) ^ 5 Push
+D*(C^B+A) ^ 5E Push
+*+A^BCD^E5
Result
+*+A^BCD^E5