Module 3 Queues
Module 3 Queues
Queues and Lists – The Queue and its sequential representation, Linked Lists, Lists in C. Other Lists structures – Circular Lists, Stacks, Queues as
circular list. The Josephus problem, doubly linked lists. Linked lists and Queues - Text Book -1-Chapter – 4.1-4.3,4.5
A Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of “First in, First out” (FIFO), where the
first element added to the queue is the first one to be removed. Queues are commonly used in various algorithms and applications for their simplicity and efficiency in managing data flow.
A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. It operates like a line where elements are added at one end (rear) and removed from the
Dequeue (Delete): Removes and returns the element from the front of the queue.
Peek: Returns the element at the front of the queue without removing it.
Applications of Queue
Implementation of Queues
o rear is the index up to which the elements are stored in the array and
o front is the index of the first element of the array.
Enqueue: Addition of an element to the queue. Adding an element will be performed after checking whether the queue is full or not. If rear == size then it is said to be an
Overflow condition as the array is full.else which indicates that the array is not full then store the element at arr[rear] and increment rear by 1 .
Dequeue: Removal of an element from the queue. An element can only be deleted when there is at least an element to delete. If front == rear, then it is said to be an
Underflow condition as the array is empty . else, the element at arr[front] can be deleted but all the remaining elements have to shift to the left by one position in order for
the dequeue operation to delete the second element from the left on another dequeue operation.
Front: Get the front element from the queue i.e. arr[front] if the queue is not empty.
Display: Print all elements of the queue. If the queue is non-empty, traverse and print all the elements from the index front to rear.
if (isFull(queue))
return;
queue->rear = (queue->rear + 1) % queue->capacity;
queue->array[queue->rear] = item;
queue->size = queue->size + 1;
printf("%d enqueued to queue\n", item);
}
// Function to remove an item from queue.
// It changes front and size
int dequeue(struct Queue* queue)
{
if (isEmpty(queue))
return INT_MIN;
int item = queue->array[queue->front];
queue->front = (queue->front + 1) % queue->capacity;
queue->size = queue->size - 1;
return item;
}
// Function to get front of queue
int front(struct Queue* queue)
{
if (isEmpty(queue))
return INT_MIN;
return queue->array[queue->front];
}
// Function to get rear of queue
int rear(struct Queue* queue)
{
if (isEmpty(queue))
return INT_MIN;
return queue->array[queue->rear];
}
// Driver program to test above functions./
int main()
{
struct Queue* queue = createQueue(1000);
enqueue(queue, 10);
enqueue(queue, 20);
enqueue(queue, 30);
enqueue(queue, 40);
printf("%d dequeued from queue\n\n", dequeue(queue));
printf("Front item is %d\n", front(queue));
printf("Rear item is %d\n", rear(queue));
return 0;
}
Output
10 enqueued to queue
20 enqueued to queue
30 enqueued to queue
40 enqueued to queue
10 dequeued from queue
Front item is 20
Rear item is 40
Linked Lists,
A linked list is a fundamental data structure in computer science. It consists of nodes where each node contains data and a reference (link) to the next node in the sequence. This allows for
dynamic memory allocation and efficient insertion and deletion operations compared to arrays.
A linked list is a linear data structure that consists of a series of nodes connected by pointers. Each node contains data and a reference to the next node in the list. Unlike arrays, linked lists
allow for efficient insertion or removal of elements from any position in the list, as the nodes are not stored contiguously in memory.
Linked List:
Insertion/Deletion: Efficient
Access: Sequential
Array:
Insertion/Deletion: Inefficient
Access: Random
// Deletion
deleteNode(&head, 20);
printf("Linked List after deletion of 20: ");
traverse(head);
// Searching
int key = 10;
if (search(head, key)) {
printf(“Element %d is found in the linked list.\n”, key);
} else {
printf(“Element %d is not found in the linked list.\n”, key);
}
// Traversal
printf(“Final Linked List: “);
traverse(head);
return 0;
}
Output
Linked List after insertions: 5 -> 10 -> 20 -> 30 -> NULL
Linked List after deletion of 20: 5 -> 10 -> 30 -> NULL
Element 10 is found in the linked list.
Final Linked List: 5 -> 10 -> 30 -> NULL
Advantages of a Linked List
Linked list is dynamic data structure it has memory allocation and de-allocation, which means that memory is only used when needed and not earlier in order to avoid waste.
In linked list items are arranged in a linear fashion, new items can be inserted or removed as and when needed without affecting other items on the list, which makes these
processes efficient.
Memory is utilized effectively since nodes are created on-demand, which means that memory is not pre-allocated when the system has less load.
Several linear data structures, like stacks and queues, can be implemented with the help of linked lists.
Disadvantages of a Linked List
In a linked list whenever we want to find the element with position n, all the other elements must be visited first, and this could take quite a lot of time.
In a linked list, there is more memory needed than there is with an array because each node contains some pointer information.
An operation that involves accessing elements of a linked list is not as simple as that in an array since elements of a linked list do not have indices that would help you jump to a
given position directly.
Reversing a linked list involves more than one level of pointer arrows in a singly linked list is not feasible or efficient.
Applications of Linked Lists
The following are the applications of linked list:
Linked list are commonly used to implement stacks and queues.
It can be used to implement graphs, with the adjacent vertices stored in the nodes of the linked list.
It can be used in dynamic memory allocation.
It is used for representing sparse matrices.
It can be used to store and manipulate polynomials.
Linked list is used in operating systems to manage task scheduling.
It is also used in compilers to build a symbol table.
Lists in C.
The circular linked list is a version of a linked list where the last node does not point to the NULL, but instead, it points back to the first node making a circular loop-like structure.
A circular linked list is a data structure in which the last node points to the first node, thus forming a circular loop. It is a variation of the traditional singly linked list, where each node points
The advantage of this kind of linked list is that you can assume any node as the head and traverse the whole linked list from that node.
In C, each node of the linked list can be represented as a structure with a data field and a pointer to the next node in the sequence. The whole linked list is represented by the pointer to
We can then define the functions to perform the basic operations like insertion, deletion, and traversal. While implementing these functionalities, we have to be extra careful in keeping
the check for the end of the linked list as it may easily lead to an infinite loop if missed.
#include <stdio.h>
#include <stdlib.h>
// Structure for a node
struct Node {
int data; // represent application data
struct Node* next; // support for logical linkage between diff elements
};
// Function to insert a node at the beginning of a Circular linked list
void push(struct Node** head_ref, int data)
{
// Create a new node and make head as next of it.
struct Node* ptr1 = (struct Node*)malloc(sizeof(struct Node));
ptr1->data = data;
ptr1->next = *head_ref;
// If linked list is not NULL then set the next of last node
if (*head_ref != NULL)
{
// Find the node before head and update next of it.
struct Node* temp = *head_ref;
while (temp->next != *head_ref)
temp = temp->next;
temp->next = ptr1;
}
else // // insert node for the first time
{
// For the first node
ptr1->next = ptr1;
}
*head_ref = ptr1;
}
// Function to print nodes in a given circular linked list
void printList(struct Node* head)
{
struct Node* temp = head; // use local pointer (temp) for traversal
if (head != NULL) {
do {
printf("%d ", temp->data);
temp = temp->next;
} while (temp != head);
}
printf("\n");
}
// Function to delete a given node from the list
void deleteNode(struct Node** head, int key)
{
// If linked list is empty
if (*head == NULL)
return;
// If the list contains only a single node
if ((*head)->data == key && (*head)->next == *head) {
free(*head);
*head = NULL;
return;
}
struct Node *last = *head, *d;
// If head is to be deleted
if ((*head)->data == key) {
// Find the last node of the list
while (last->next != *head)
last = last->next;
// Point last node to the next of head i.e. the second node
// of the list
last->next = (*head)->next;
free(*head);
*head = last->next;
return;
}
// Either the node to be deleted is not found or the end of list
// is not reached
while (last->next != *head && last->next->data != key) {
last = last->next;
}
// If node to be deleted was found
if (last->next->data == key) {
d = last->next;
last->next = d->next;
free(d);
}
else
printf("Given node is not found in the list!!!\n");
}
// Driver code
int main()
{
// Initialize lists as empty
struct Node* head = NULL;
// Created linked list will be
// 2->5->7->8->10
push(&head, 2);
push(&head, 5);
push(&head, 7);
push(&head, 8);
push(&head, 10);
printf("List Before Deletion: ");
printList(head);
deleteNode(&head, 7);
printf("List After Deletion: ");
printList(head);
return 0;
}
Output
pointer to the last inserted node and the front can always be obtained as next of last.
Circular lists are useful in applications to repeatedly go around the list. For example, when multiple applications are running on a PC, it is common for the operating system to
put the running applications on a list and then cycle through them, giving each of them a slice of time to execute, and then making them wait while the CPU is given to another
application. It is convenient for the operating system to use a circular list so that when it reaches the end of the list it can cycle around to the front of the list.
Circular Doubly Linked Lists are used for the implementation of advanced data structures like the Fibonacci Heap.
Implementing a circular linked list can be relatively easy compared to other more complex data structures like trees or graphs.
be sorted or searched.
Circular linked lists don’t provide direct access to individual nodes
Circular queues are a typical data structure in operating systems. It is employed to control how computer programs or procedures are carried out. To hold the processes in the order of
their insertion, you use a circular queue as a buffer. When allocating resources or executing them, you then remove the processes from the queue.
A circular queue is an expanded version of a linear queue that adheres to the First In First Out tenet, with the difference that it forms a circular link from the final node of the queue to the
first. It is also known as a Ring Buffer as result.
The Circular Queue is comparable to a Linear Queue in that it adheres to the FIFO (First In First Out) concept, but it varies in that the end position is linked to the first
enQueue(value) – utilized to add a fresh value to the circular queue. This procedure begins at the end of the queue.
deQueue() – Used to delete a value from the Circular Queue. From the head of the queue, this operation is performed.
While implementing a circular queue using a linked list, the queue has two main actions, Enqueue() and Dequeue() let you control how the data flows. These opera-
tions need constant execution time, or O(1), because they are independent of the queue’s size or the number of entries it contains.
Enqueue(x) Operation
The steps to insert the element in the circular queue are as follows:
Step 3: If the line is empty, verify that the Front and Rear are both set to 0.
Step 4: Rear should be set to 0 if Rear = Maxsize – 1 & Front!= 0 (rear pointer is at the end of the queue and front is not at index 0).
Step 7: End
Deque Operation
Accessing the data where the front is pointing and removing the data after access are the two subtasks that makeup getting data from the queue.
Step 1: If the front and back of the queues are both -1, the queue is empty.
Step 4: Set Front and Rear to -1 (IF Front = Rear, set Front = Rear = -1) if a queue only has one element.
Step 7: End
The C programming language’s linked list implementation of a circular queue is shown below.
#include <stdio.h>
struct node
{
int data;
struct node *next;
};
// external pointers to hold the front and rear end of the circular queue
struct node *front=-1;
struct node *rear=-1;
// Add an element into the Circular Queue (CQ)
void enqueue(int x)
{
struct node *newnode;
newnode=(struct node *)malloc(sizeof(struct node));
newnode->data=x;
newnode->next=0;
if(rear==-1) // add an element into empty CQ
{
front=rear=newnode;
rear->next=front;
}
}
// function to display all the elements of the queue
void display()
{
struct node *temp;
temp=front;
printf("\n The elements in a Queue are : ");
if((front==-1) && (rear==-1))
{
printf("Queue is empty");
}
else
{
while(temp->next != front)
{
printf("%d,", temp->data);
temp=temp->next;
}
printf("%d", temp->data);
}
}
void main()
{
enqueue(14);
enqueue(11);
enqueue(13);
display();
dequeue();
peek();
}
In computer science and mathematics, the Josephus problem (or Josephus permutation) is a theoretical problem related to a certain counting-out game. Such games are used to pick out a
person from a group, e.g. eeny, meeny, miny, moe.
A drawing for the Josephus problem sequence for 500 people and skipping value of 6. The horizontal axis is the number of the person. The vertical axis (top to bottom) is time (the number of
cycle). A live person is drawn as green, a dead one is drawn as black.
In the particular counting-out game that gives rise to the Josephus problem, a number of people are standing in a circle waiting to be executed. Counting begins at a specified point in the
circle and proceeds around the circle in a specified direction. After a specified number of people are skipped, the next person is executed. The procedure is repeated with the remaining
people, starting with the next person, going in the same direction and skipping the same number of people, until only one person remains, and is freed.
The problem—given the number of people, starting point, direction, and number to be skipped—is to choose the position in the initial circle to avoid execution.
There are N people standing in a circle waiting to be executed. The counting out begins at some point in the circle and proceeds around the circle in a fixed direction. In each step, a certain
number of people are skipped and the next person is executed. The elimination proceeds around the circle (which is becoming smaller and smaller as the executed people are removed), until
only the last person remains, who is given freedom.
Given the total number of persons N and a number k which indicates that k-1 persons are skipped and the kth person is killed in a circle. The task is to choose the person in the initial circle
that survives.
Input: N = 5 and k = 2
Output: 3
Explanation: Firstly, the person at position 2 is killed,
then the person at position 4 is killed, then the person at position 1 is killed.
Finally, the person at position 5 is killed. So the person at position 3 survives.
Input: N = 7 and k = 3
Output: 4
Explanations: The persons at positions 3, 6, 2, 7, 5, and 1 are killed in order,
and the person at position 4 survives.
The simple approach is to create a list and add all values from 1 to N to it. Create a recursive function that takes a list, start (position at which counting will start), and k ( number of people to be skipped) as
an argument. If the size of the list is one i.e. only one person left then return this position. Otherwise, start counting the k person in a clockwise direction from starting position and remove the person at the
kth position. Now the person at the kth position is removed and now counting will start from this position. This process continues till only one person is left.
Pseudocode :
if list.size = 1
return list[0]
list.remove( start )
Illustration:
N = 5, k = 2
Add all values from 1 to N in the list. We will call the recursive function with start = 0 and k = 1 (0-indexing)
Now the element at 1-index (person number 2) will be killed. And it is removed from the list. The new counting will begin from 1-index, the person
at 1-index killed so now person at 2-index (person number 3) comes to 1-index and counting starts from here now.
Now we have 4 people, counting starting from 1-index (person number 3) and the person at kth (2-index ) position will be killed.
The person at 2-index (person number 4) was killed so now we have 3 people left and the person (person number 5) at 3-index shifted to 2-index.
The person at the 0-index was killed and we have now two-person left in the circle. And the person at 1-index shifted to 0-index i.e. person number
3.
Final counting done and the person at 1-index killed and the only person who is left is at position 3.
There are N people standing in a circle numbered from 1 to N. Also given an integer K. First, count the K-th number starting from the first one and delete it. Then K numbers
are counted starting from the next one and the K-th one is removed again, and so on. The process stops when one number remains. The task is to find the last number.
/*
* C Program to Solve Josephus Problem using Linked List
*/
#include <stdio.h>
#include <stdlib.h>
struct node
{
int num;
struct node *next;
};
void create(struct node **);
void display(struct node *);
int survivor(struct node **, int);
int main()
{
struct node *head = NULL;
int survive, skip;
create(&head);
printf("The persons in circular list are:\n");
display(head);
printf("Enter the number of persons to be skipped: ");
scanf("%d", &skip);
A doubly linked list is a type of linked list in which each node has two links. The first link points to the previous node in the list while the second link points to the
next node in the list. In other words, navigation in a doubly linked list is possible from both sides, from the front as well as the back. In this article, we will learn
how to create a doubly linked list in C.
What is a Doubly Linked List?
In a singly linked list, each node has only one link which points to the node next to it. For this reason, we can traverse it from one side only and we cannot traverse
back and forth. To solve this problem doubly linked list is used where each node contains a link to the next as well as the previous node.
How We Can Create a Doubly Linked List in C?
To create a Doubly Linked List in C, you need to define a structure that represents each node in the list. Each node should contain pointers to the previous and next
nodes. Then, you can define functions to perform operations such as insertion, deletion, and traversal on the doubly linked list.
1. Representation
The doubly linked list node can be represented as a structure in C language. The below structure represents the minimal doubly linked list:
typedef struct node {
int data;
struct node* next;
struct node* prev;
} Node;
Here,
data: data field of the node.
next: pointer to the next node.
prev: pointer to the prev node.
The nodes at the ends (i.e. does not have a previous or next node) will be set as NULL.
We can then use this data type with malloc() to dynamically create the instances of the doubly linked list node and then join them inside insertion operations.
The whole doubly linked list will be represented as the pointer to the head node (i.e. starting node) as all the nodes can be traversed using this node. We can also maintain a pointer to the end
node for our convenience.
2. Basic Operations
The basic operations that are performed on the double linked list in this program are as follows:-
To add an element to the end of the doubly O(1), if we have pointer to tail, other-
Insert_at_tail O(1)
linked list. wise O(N).
Delete an element from the end of the doubly O(1), if we have pointer to tail, other-
Delete_at_tail O(1)
linked list. wise O(N).
insert_at_head(20);
insert_at_tail(30);
display_forward(); // expected output: 20 10 30
display_backward(); // expected output: 30 10 20
delete_at_head(); // delete 20
delete_at_tail(); // delete 30
display_forward(); // expected output: 10
display_backward(); // expected output: 10
return 0;
}