Data SC5
Data SC5
Queue 5
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.
Enqueue
(Insertion)
APPLICATIONS OF QUEUE
Due to the fact that queue performs actions on first in first out basis which
is quite fair for the ordering of actions. There are various applications of queues
discussed as below.
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.
128 Data Structures
Complexity
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:
[Link]
o Linked list allocation: The linked list allocation in a Queue can be
implemented using a linked list.
For more details, click on the below link:
[Link]
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:
10 20 30
front rear
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:
20 30
front rear
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.
130 Data Structures
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:
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.
H E L L O
0 1 2 3 4 5
front rear
0 4
Queue
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.
132 Data Structures
H E L L O G
0 1 2 3 4 5
front rear
0 5
Queue after inserting an element
E L L O G
0 1 2 3 4 5
front rear
1 5
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. }
134 Data Structures
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. {
7. printf(“underflow”);
8. }
9. else
10. {
11. y = queue[front];
12. if(front == rear)
13. {
14. front = rear = –1;
15. else
16. front = front + 1;
17.
Queues 135
18. }
19. return y;
20. }
21. }
26. break;
27. case 3:
28. display();
29. break;
30. case 4:
31. exit(0);
32. break;
33. default:
34. printf(“\nEnter valid choice??\n”);
35. }
36. }
37. }
38. void insert()
39. {
40. int item;
41. printf(“\nEnter the element\n”);
42. scanf(“\n%d”,&item);
43. if(rear == maxsize–1)
44. {
45. printf(“\nOVERFLOW\n”);
46. return;
47. }
48. if(front == –1 && rear == –1)
49. {
50. front = 0;
51. rear = 0;
52. }
53. else
54. {
55. rear = rear+1;
56. }
57. queue[rear] = item;
Queues 137
90. int i;
91. if(rear == –1)
92. {
93. printf(“\nEmpty queue\n”);
94. }
95. else
96. { printf(“\nprinting values .....\n”);
97. for(i=front;i<=rear;i++)
98. {
99. printf(“\n%d\n”,queue[i]);
100. }
101. }
102. }
Output:
*************Main Menu**************
==============================================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?1
Enter the element
123
Value inserted
*************Main Menu**************
==============================================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?1
Queues 139
0 1 2 3 4 5 6 7 8 9
front rear
Limitation of array representation of queue
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 can not
reinsert the values in the place of already deleted element before the position of
front. That much space of the array is wasted and can not be used in the future
(for this queue).
9 1 7 4
front rear
Insert operation
The insert operation append the queue by adding an element to the end of
the queue. The new element will be the last element of the queue.
Firstly, allocate the memory for the new node ptr by using the following
statement.
1. Ptr = (struct node *) malloc (sizeof(struct node));
There can be the two scenario of inserting this new node ptr into the linked
queue.
142 Data Structures
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.
1. ptr –> data = item;
2. if(front == NULL)
3. {
4. front = ptr;
5. rear = ptr;
6. front –> next = NULL;
7. rear –> next = NULL;
8. }
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.
1. rear –> next = ptr;
2. rear = ptr;
3. rear–>next = NULL;
In this way, the element is inserted into the queue. The algorithm and the C
implementation is given as follows.
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
Queues 143
C Function
1. void insert(struct node *ptr, int item; )
2. {
3.
4.
6. if(ptr == NULL)
7. {
8. printf(“\nOVERFLOW\n”);
9. return;
10. }
11. else
12. {
15. {
20. }
21. else
22. {
26. }
27. }
28. }
144 Data Structures
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);
Algorithm
o Step 1: IF FRONT = NULL
Write “ Underflow “
Go to Step 5
[END OF IF]
o Step 2: SET PTR = FRONT
o Step 3: SET FRONT = FRONT –> NEXT
o Step 4: FREE PTR
o Step 5: END
C Function
1. void delete (struct node *ptr)
2. {
3. if(front == NULL)
4. {
5. printf(“\nUNDERFLOW\n”);
6. return;
7. }
8. else
Queues 145
9. {
10. ptr = front;
11. front = front –> next;
12. free(ptr);
13. }
14. }
54. {
55. printf(“\nEnter value?\n”);
56. scanf(“%d”,&item);
57. ptr –> data = item;
58. if(front == NULL)
59. {
60. front = ptr;
61. rear = ptr;
62. front –> next = NULL;
63. rear –> next = NULL;
64. }
65. else
66. {
67. rear –> next = ptr;
68. rear = ptr;
69. rear–>next = NULL;
70. }
71. }
72. }
73. void delete ()
74. {
75. struct node *ptr;
76. if(front == NULL)
77. {
78. printf(“\nUNDERFLOW\n”);
79. return;
80. }
81. else
82. {
83. ptr = front;
84. front = front –> next;
85. free(ptr);
148 Data Structures
86. }
87. }
88. void display()
89. {
90. struct node *ptr;
91. ptr = front;
92. if(front == NULL)
93. {
94. printf(“\nEmpty queue\n”);
95. }
96. else
97. { printf(“\nprinting values .....\n”);
98. while(ptr != NULL)
99. {
100. printf(“\n%d\n”,ptr –> data);
101. ptr = ptr –> next;
102. }
103. }
104. }
Output:
***********Main Menu**********
==============================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?1
Enter value?
123
***********Main Menu**********
==============================
Queues 149
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?1
Enter value?
90
***********Main Menu**********
==============================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?3
printing values .....
123
90
***********Main Menu**********
==============================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?2
***********Main Menu**********
==============================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?3
printing values .....
150 Data Structures
90
***********Main Menu**********
==============================
1. insert an element
2. Delete an element
3. Display the queue
4. Exit
Enter your choice ?4
CIRCULAR QUEUE
Front = 3 Rear = 4
1 2
0 1 2 3 4
4
2
1
1
3
2
Queues 151
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.
o CPU Scheduling: The operating system also uses the circular queue to
insert the processes and then execute them.
o Traffic system: In a computer–control traffic system, traffic light is one
of the best examples of the circular queue. Each light of traffic light gets
ON one by one after every jinterval of time. Like red light gets ON for
one minute then yellow light for one minute and then green light. After
green light, the red light gets ON.
Enqueue operation
The steps of enqueue operation are given below:
o First, we will check whether the Queue is full or not.
o Initially the front and rear are set to –1. When we insert the first
element in a Queue, front and rear both are set to 0.
o When we insert a new element, the rear gets incremented,
i.e., rear=rear+1.
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.
0 1 2 3 4
Front = –1
Rear = –1
10
0 1 2 3 4
Front = 0
Rear = 0
10 20 30
Front = 0 Rear = 0
10 20 30 40
0 1 2 3 4
Front = 0 Rear = 3
10 20 30 40 50
0 1 2 3 4
Front = 0 Rear = 4
30 40 50
0 1 2 3 4
dequeue
Front = 2 Rear = 4
Queues 155
60 30 40 50
0 1 2 3 4
Rear Front
60 70 30 40 50
0 1 2 3 4
Rear Front
20. else
21. {
22. rear=(rear+1)%max; // rear is incremented
23. queue[rear]=element; // assigning a value to the
queue at the rear position.
24. }
25. }
26.
27. // function to delete the element from the queue
28. int dequeue()
29. {
30. if((front==–1) && (rear==–1)) // condition to check queue is empty
31. {
32. printf(“\nQueue is underflow..”);
33. }
34. else if(front==rear)
35. {
36. printf(“\nThe dequeued element is %d”, queue[front]);
37. front=–1;
38. rear=–1;
39. }
40. else
41. {
42. printf(“\nThe dequeued element is %d”, queue[front]);
43. front=(front+1)%max;
44. }
45. }
46. // function to display the elements of a queue
47. void display()
48. {
49. int i=front;
50. if(front==–1 && rear==–1)
Queues 157
51. {
52. printf(“\n Queue is empty..”);
53. }
54. else
55. {
56. printf(“\nElements in a Queue are :”);
57. while(i<=rear)
58. {
59. printf(“%d,”, queue[i]);
60. i=(i+1)%max;
61. }
62. }
63. }
64. int main()
65. {
66. int choice=1,x; // variables declaration
67.
68. while(choice<4 && choice!=0) // while loop
69. {
70. printf(“\n Press 1: Insert an element”);
71. printf(“\nPress 2: Delete an element”);
72. printf(“\nPress 3: Display the element”);
73. printf(“\nEnter your choice”);
74. scanf(“%d”, &choice);
75.
76. switch(choice)
77. {
78.
79. case 1:
80.
81. printf(“Enter the element which is to be inserted”);
82. scanf(“%d”, &x);
158 Data Structures
83. enqueue(x);
84. break;
85. case 2:
86. dequeue();
87. break;
88. case 3:
89. display();
90. }
91. }
92. return 0;
93. }
Output :
Press 1 : Insert an element
Press 2 : Delete an element
Press 3 : Display the element
Enter your choice
1
Enter the element which is to be inserted
10
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;
160 Data Structures
40. {
41. front=rear=-1;
42. free(temp);
43. }
44. else
45. {
46. front=front->next;
47. rear->next=front;
48. free(temp);
49. }
50. }
51.
52. // function to get the front of the queue
53. int peek()
54. {
55. if((front==-1) &&(rear==-1))
56. {
57. printf(“\nQueue is empty”);
58. }
59. else
60. {
61. printf(“\nThe front element is %d”, front->data);
62. }
63. }
64.
65. // function to display all the elements of the queue
66. void display()
67. {
68. struct node *temp;
69. temp=front;
70. printf(“\n The elements in a Queue are : ”);
71. if((front==-1) && (rear==-1))
72. {
162 Data Structures
88. {
89. enqueue(34);
90. enqueue(10);
91. enqueue(23);
92. display();
93. dequeue();
94. peek();
95. }
Output:
elements in a priority queue will determine the order in which elements are
removed from the priority queue.
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.
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.
2 6 7 10 11
10 9 8 7 6
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:
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.
Queues 167
Max heap
45
30 40
20 10 35 15
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.
Min heap
6 7
8 9 14 20
Both the heaps are the binary heap, as each has exactly two child nodes.
node; if it is found out of order, elements are swapped. This process continues
until the element is placed in a correct position.
20
1 2
17 16
New Element
3 4 5 6
15 14 13 18
Heapify
0
20
1 2
17 18
3 4 5 6
15 14 13 16
Program to create the priority queue using the binary max heap.
1. #include <stdio.h>
2. #include <stdio.h>
3. int heap[40];
4. int size=-1;
5.
6. // retrieving the parent node of the child node
7. int parent(int i)
8. {
9.
10. return (i - 1) / 2;
11. }
12.
13. // retrieving the left child of the parent node.
14. int left_child(int i)
15. {
16. return i+1;
17. }
18. // retrieving the right child of the parent
19. int right_child(int i)
20. {
21. return i+2;
22. }
23. // Returning the element having the highest priority
24. int get_Max()
25. {
26. return heap[0];
27. }
170 Data Structures
122. insert(16);
123. insert(14);
124. int i=0;
125.
126. printf(“Elements in a priority queue are : ”);
128. {
130. }
134. {
136. }
139.
140.
143. return 0;
144. }
o int right_child(int i): This function returns the index of the right child
of a given index, i.e., i.
o void moveUp(int i): This function will keep moving the node up the
tree until the heap property is restored.
o void moveDown(int i): This function will keep moving the node down
the tree until the heap property is restored.
o void removeMax(): This function removes the element which is having
the highest priority.
o void insert(int p): It inserts the element in a priority queue which is
passed as an argument in a function.
o void delete(int i): It deletes the element from a priority queue at a
given index.
o int get_Max(): It returns the element which is having the highest
priority, and we know that in max heap, the root node contains the
element which has the largest value, and highest priority.
o int get_Min(): It returns the element which is having the minimum
priority, and we know that in max heap, the last node contains the
element which has the smallest value, and lowest priority.
Output :
Elements in a priority queue are : 21 19 20 18 12 17 15 16 14
Elements in a priority queue after deleting the element are :
21 19 18 17 12 16 15 14
....Program finished with exit code 0
Press Enter to exit console.
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.
Queues 175
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 –
enqueue() – add (store) an item to the queue.
dequeue() – remove (access) an item from the queue.
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.
Let’s first learn about supportive functions of a queue –
peek()
This function helps to see the data at the front of the queue. The algorithm
of peek() function is as follows –
Algorithm
begin procedure peek
return queue[front]
end procedure
Implementation of peek() function in C programming language –
Example
int peek() {
return queue[front];
}
isfull()
Algorithm
begin procedure isfull
return true
else
return false
endif
end procedure
return true;
else
return false;
}
isempty()
return false
endif
end procedure
If the value of front is less than MIN or 0, it tells that the queue is not yet
initialized, hence empty.
Here’s the C programming code –
Queues 177
Example
bool isempty() {
if(front < 0 || front > rear)
return true;
else
return false;
}
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.
Example
int enqueue(int data)
if(isfull())
return 0;
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.
if queue is empty
return underflow
end if
data = queue[front]
front ? front + 1
return true
end procedure
Queues 179
Rules
The mission is to move all the disks to some another tower without violating
the sequence of arrangement. A few rules to be followed for Tower of Hanoi are –
Only one disk can be moved among the towers at any given time.
Only the “top” disk can be removed.
No large disk can sit over a small disk.
Following is an animated representation of solving a Tower of Hanoi puzzle
with three disks.
Tower of Hanoi puzzle with n disks can be solved in minimum 2n–1 steps.
This presentation shows that a puzzle with 3 disks has taken 23 – 1 = 7 steps.
Algorithm
To write an algorithm for Tower of Hanoi, first we need to learn how to
solve this problem with lesser amount of disks, say 1 or 2. We mark three
towers with name, source, destination and aux (only to help moving the disks). If
we have only one disk, then it can easily be moved from source to destination peg.
If we have 2 disks –
180 Data Structures
Example – a function that calls another function which in turn calls it again.
int function1(int value1) {
if(value1 < 1)
return;
function2(value1 – 1);
printf(“%d “,value1);
}
int function2(int value2) {
function1(value2);
}
PROPERTIES
A recursive function can go infinite like a loop. To avoid infinite running of
recursive function, there are two properties that a recursive function must have –
Base criteria – There must be at least one base criteria or condition,
such that, when this condition is met the function stops calling itself
recursively.
Progressive approach – The recursive calls should progress in such a
way that each time a recursive call is made it comes closer to the base
criteria.
IMPLEMENTATION
Many programming languages implement recursion by means of stacks.
182 Data Structures
Analysis of Recursion
One may argue why to use recursion, as the same task can be done with
iteration. The first reason is, recursion makes a program more readable and
because of latest enhanced CPU systems, recursion is more efficient than
iterations.
Time Complexity
In case of iterations, we take number of iterations to count the time
complexity. Likewise, in case of recursion, assuming everything is constant, we
try to figure out the number of times a recursive call is being made. A call made
to a function is O(1), hence the (n) number of times a recursive call is made
makes the recursive function O(n).
Space Complexity
Space complexity is counted as what amount of extra space is required for a
module to execute. In case of iterations, the compiler hardly requires any extra
space. The compiler keeps updating the values of variables used in the iterations.
But in case of recursion, the system needs to store activation record each time a
recursive call is made. Hence, it is considered that space complexity of recursive
function may go higher than that of a function with iteration.
________