Data Structures and Algorithms Lecture (8): Queues - University of Science and Technology

Document Details

StylishSpessartine

Uploaded by StylishSpessartine

University of Science and Technology

Prof. Noureldien A. Noureldien

Tags

data structures algorithms queues computer science

Summary

This document provides an overview of queues, a fundamental data structure in computer science. It details the concept of queues, linear representations using arrays and linked lists, basic operations, and compares different implementations. The document also discusses applications.

Full Transcript

**University of Science and Technology** **Faculty of Computer Science and Information Technology** **Data Structures and Algorithms** **Lecture (8): Queues** **Prof. Noureldien A. Noureldien** **8.1 Linear Queue** The queue is also another useful non-primitive linear data structure in compute...

**University of Science and Technology** **Faculty of Computer Science and Information Technology** **Data Structures and Algorithms** **Lecture (8): Queues** **Prof. Noureldien A. Noureldien** **8.1 Linear Queue** The queue is also another useful non-primitive linear data structure in computer science. A real-life example of the queue is line or sequence of people or vehicles awaiting their turn to be attended to or to proceed. ***Definition:*** A queue is a homogeneous collection of elements in which deletions can take place only at the front end, known as dequeue and insertions can take place only at the rear end, known as enqueue. The element to enter the queue first will be deleted from the queue first. That is why a queue is called **First-In-First-Out (FIFO)** system. The concept of the queue can be understood by our real life problems. For example, a customer comes and join in a queue to take the train ticket at the end (rear) and the ticket is issued from the front end of the queue. That is, the customer who arrived first will receive the ticket first. It means the customers are serviced in the order in which they arrive at the service center. **8.1.1 Operations on Queue** The queue is an abstract data type since it is defined in terms of operations on it and its implementation is hidden. Therefore, the queue can be implemented with an array or with the help of the linked list. The queue includes a finite sequence of the same type of items with the different operations described in table 6.3. The differences between stacks and queues are shown in table 6.4. ![](media/image2.png) **8.1.2 Queue Representation with Array** **[The array can be used to implement a queue of fixed size, therefore only fixed a number of data items can be inserted and deleted]**. Consider the following example, the queue of size 5, therefore, maximum only 5 data items can be inserted. ***The front index always keeps track of the last deleted item*** from the queue and ***rear index always keep track of the last inserted item in the queue***. Initially, front and rear both are initialized by -1 (for the zero-based array) when there are no items in the queue, i.e. the queue is empty. **[When a new item is inserted in the queue, the rear is incremented by 1 before the item is stored in the queue]**. Once all the five items are inserted, then rear is 4, as shown in the figure 6.4. Now, if we try to insert next item, it leads to an overflow condition. It indicates that the queue is full and we cannot insert the new item. ![](media/image4.png) **[When an item is deleted from the queue, the front is incremented by 1, before the item is removed from the queue.]** Now, if front = rear then if we try to delete an item, it results in underflow condition. It indicates that the queue is empty and we cannot delete an item. Whenever the queue is found empty, then to reuse the empty slots at the front of the queue we can reset the front and rear by -1. ![](media/image6.png) Therefore, it is required to check overflow and underflow conditions whenever insertions and deletions operations take place. **8.1.3 Queue Representation with Linked List** Singly linked list can be used to represent a queue, which is also known as **Linked Queue.** In this representation, any number of data items can be inserted and deleted. **[The front and rear pointers always keep track of the first node and the last node in the linked list respectively]**. Initially, front and rear are initialized by null (i.e. front = rear = null), when there are no items in the ***queue, that means the queue is empty*[. The linked list header acts as the front of the queue.]** All deletion operations take place at the front of the list. **All insertion operations take place at the end of the list**. If the queue contains a single element then front and rear points to head/new node (i.e. front = rear = head). When a new item is inserted in the queue, a new node is inserted at the end of the linked **list, the rear points to the new node**. When an item is deleted from the queue, the node from the front of the queue is deleted. Now, if front = null then if we try to delete an item, it results in underflow condition. It indicates that the queue is empty and we cannot delete an item. **[Whenever the queue is found empty, we can reset the front and rear by null.]** ![](media/image8.png) **8.1.4 Comparisons of َ Queue Representation Using Linked List over the Array** The array is fixed size, therefore, a number of elements will be limited in the queue. Since linked list is dynamic and can be changed easily, so the number of elements can be changed. The pointers in linked list consume additional memory compared to an array. In array implementation, sometimes dequeue operation not possible, although there are free slots. This drawback can be overcome in linked list representation. In array and linked list enqueue and dequeue operations can be done in O (1). **8.1.5 Application of Queues** A major application of the queue is in simulation. In operating systems, queues are used for process management, I/O request handling, etc. ***Examples***: Print queue of DOS, Message queue of Unix IPC. Queues are also used in some elegant algorithms like graph algorithms (breadth first search), radix sort etc. Different types of customer service software are designed using a queue for proper service to the customer. ***Example:*** Railway ticket reservation system **8.1.6 Drawbacks of Linear Queue** The linear queue, when represented using an array, suffers from drawbacks. Once the queue is full, even though few elements are deleted from the front end and some free slots are created, it is not possible to insert new elements, as the rear has already reached the queue's rear most position. Consider the figure, the queue of size 5 and the front is 2, rear is 4. Now, we are not able to insert new data item into the queue, although there are free slots (first and second location) in the front of the queue, because of rigid rule followed by linear queue (insertion can be done at the rear end of the queue). **[It is also known as a boundary case problem.]** **8.2 Circular Queue** A circular queue (also known as a circular buffer) is a linear data structure that uses a single, fixed-size buffer as if it were connected end-to-end. A circular queue is just one of the efficient ways to implement a queue. It also follows First-in-First-out (FIFO) principle. There was one limitation in the array implementation of [Queue](https://www.javatpoint.com/data-structure-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. **8.2.1 Circular Queue Representation with Array** In array representation, the queue is considered as circular queue when the positions 0 and MAX-1 are adjacent. It means when rear (or front) reaches MAX-1 position then increment in rear (or front) causes rear (or front) to reach the first position that is 0. Figure (6.5) shows how circular queue works. ![](media/image10.png) **8.2.2 Operations on Circular Queue** The following are the operations that can be performed on a circular queue: - **Front:** It is used to get the front element from the Queue. - **Rear:** It is used to get the rear element from the Queue. - **enQueue(value):** This function is used to insert the new value in the Queue. The new element is always inserted from the rear end. - **deQueue():** This function deletes an element from the Queue. The deletion in a Queue always takes place from the front end. **8.2.3 Applications of Circular Queue** The circular Queue can be used in the following applications: Memory management: The circular queue provides memory management. As we have already seen that in linear queue, the memory is not managed very efficiently. But in case of a circular queue, the memory is managed efficiently by placing the elements in a location which is unused. CPU Scheduling: The operating system also uses the circular queue to insert the processes and then execute them. 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 j interval 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. **8.2.4 Enqueue operation** **Enqueue Algorithm to insert an element in a circular queue** Add an element to the rear of the circular queue. **Steps:** - Check if the queue is full. If (rear + 1) % size == front, the queue is full. - If the queue is not full, update the rear pointer to (rear + 1) % size. - Insert the new element at the rear position. - If the queue was initially empty (i.e., front was -1), set front to 0. **Dequeue Operation** **Dequeue (Removing an element)** Remove an element from the front of the circular queue. **Steps:** - Check if the queue is empty. If front == -1, the queue is empty. - If the queue is not empty, remove the element at the front position. - Update the front pointer to (front + 1) % size. - If the queue becomes empty after the dequeue operation (i.e., front equals rear), reset both front and rear to -1. The priority queue can be represented using a (unsorted or sorted) linked list or array. For an unsorted array or for a linked list, **[insertion operation is done at the end or the head of the linked list, or at the end of the arra]**y, therefore, it runs in O (1). In the peek operation, to return the highest-priority element, **[it required searching (linear search) the highest-priority element in the entire array or the linked list]**, therefore it runs in O (n). To remove the highest-priority element, **[it required searching (linear search) the highest-priority element in the entire array or the linked list.]** In an array, we also have to shift array contents to fill the gap. Therefore, it runs in O (n). **8.3 C Implementation of Queues as Array and Linked List** Below is an example of a queue written in C that makes use of an array. 1. \#define MAX\_SIZE 100   2.    3. **int** queue\[MAX\_SIZE\];   4. **int** front = -1;   5. **int** rear = -1;   6.   // the enqueue function to insert an element into the queue 7. **void** enqueue(**int** element)  8. {   9.     **if** (rear == MAX\_SIZE - 1)  10. {   11.         printf(\"Queue is full\");   12.         **return**;   13.  }   14.     **if** (front == -1)  15. {   16.         front = 0;   17. }   18.     rear++;   19.     queue\[rear\] = element;   20. }   21. // the function dequeue to remove an element from the queue   22. **int** dequeue()  23. {   24.     **if** (front == -1 \|\| front \> rear) {   25.         printf(\"Queue is empty\");   26.         **return** -1;   27.     }   28.     **int** element = queue\[front\];   29.     front++;   30.     **return** element;   31. }   32.   // The main program 33. **int** main()  34. {   35.     enqueue(10);   36.     enqueue(20);   37.     enqueue(30);   38.     printf(\"%d \", dequeue());   39.     printf(\"%d \", dequeue());   40.     printf(\"%d \", dequeue());   41.     printf(\"%d \", dequeue());   42.     **return** 0;   43. }   The output of the code will be: **Output:** *10 20 30 Queue is empty-1* **Explanation:** 1. First, we enqueue three elements 10, 20 and 30 into the queue. 2. Then, we dequeue and print the front element of the queue, which is 10. 3. Next, we dequeue and print the front element of the queue again, which is 20. 4. Then, we dequeue and print the front element of the queue again, which is 30. 5. Finally, we make a dequeue from an empty queue that outputs \"Queue is empty\" and returns -1. Here\'s an example of a queue implemented in C using a linked list: 1. \#include\   2. \#include \   3.    4. **struct** Node {   5.     **int** data;   6.     **struct** Node\* next;   7. };   8.    9. **struct** Node\* front = NULL;   10. **struct** Node\* rear = NULL;   11.    12. **void** enqueue(**int** element) {   13.     **struct** Node\* new\_node = (**struct** Node\*)malloc(**sizeof**(**struct** Node));   14.     new\_node-\>data = element;   15.     new\_node-\>next = NULL;   16.     **if** (front == NULL && rear == NULL) {   17.         front = rear = new\_node;   18.         **return**;   19.     }   20.     rear-\>next = new\_node;   21.     rear = new\_node;   22. }   23.    24. **int** dequeue() {   25.     **if** (front == NULL) {   26.         printf(\"Queue is empty\");   27.         **return** -1;   28.     }   29.     **struct** Node\* temp = front;   30.     **int** element = temp-\>data;   31.     **if** (front == rear) {   32.         front = rear = NULL;   33.     }   34.     **else** {   35.         front = front-\>next;   36.     }   37.     free(temp);   38.     **return** element;   39. }   40. **int** main() {   41.     enqueue(10);   42.     enqueue(20);   43.     enqueue(30);   44.     printf(\"%d \", dequeue());   45.     printf(\"%d \", dequeue());   46.     printf(\"%d \", dequeue());   47.     printf(\"%d \", dequeue());   48.     **return** 0;   49. }   The output of the code will be: **Output:** *10 20 30 Queue is empty-1*

Use Quizgecko on...
Browser
Browser