0% found this document useful (0 votes)
3 views27 pages

Module 3 Queues

The document provides an overview of data structures in C, focusing on queues and linked lists, including their definitions, operations, and implementations. It details the characteristics of queues, including FIFO behavior, and discusses linked lists, their advantages, and disadvantages compared to arrays. Additionally, it covers circular linked lists and provides example code for implementing these data structures in C.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views27 pages

Module 3 Queues

The document provides an overview of data structures in C, focusing on queues and linked lists, including their definitions, operations, and implementations. It details the characteristics of queues, including FIFO behavior, and discusses linked lists, their advantages, and disadvantages compared to arrays. Additionally, it covers circular linked lists and provides example code for implementing these data structures in C.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 27

Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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

The Queue and its sequential representation,

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.

What is Queue in Data Structures?

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

other end (front).

Basic Operations of Queue Data Structure

Enqueue (Insert): Adds an element to the rear of the queue.

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.

Empty: Checks if the queue is empty.

Full: Checks if the queue is full.

Applications of Queue

Task scheduling in operating systems

Data transfer in network communication

Simulation of real-world systems (e.g., waiting lines)

Priority queues for event processing queues for event processing

Implementation of Queues

Queues can be implemented using Two techniques:

Queue Data Structure using Arrays

Queue Data Structure using Linked List

How to implement Queue using Array?

To implement a queue using an array,


 Create an array arr of size n and
 Take two variables front and rear both of which will be initialized to 0 which means the queue is currently empty.
 Element

Dr. Nataraju A B Page - 1


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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.

Now, some of the implementations of queue operations are as follows:

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.

Steps for enqueue:

Check the queue is full or not

If full, print overflow and exit

Dr. Nataraju A B Page - 2


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

If queue is not full, increment tail and add the element

Steps for dequeue:

Check queue is empty or not

if empty, print underflow and exit

if not empty, print element at the head and increment head

Below is a program to implement above operation on queue


// C program for array implementation of queue
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// A structure to represent a queue
struct Queue {
int front, rear, size;
unsigned capacity;
int* array;
};
// function to create a queue
// of given capacity.
// It initializes size of queue as 0
struct Queue* createQueue(unsigned capacity)
{
struct Queue* queue = (struct Queue*)malloc( sizeof(struct Queue));
queue->capacity = capacity;
queue->front = queue->size = 0;
// This is important, see the enqueue
queue->rear = capacity - 1;
queue->array = (int*)malloc(
queue->capacity * sizeof(int));
return queue;
}
// Queue is full when size becomes
// equal to the capacity
int isFull(struct Queue* queue)
{
return (queue->size == queue->capacity);
}
// Queue is empty when size is 0
int isEmpty(struct Queue* queue)
{
return (queue->size == 0);
}

// Function to add an item to the queue.


// It changes rear and size
void enqueue(struct Queue* queue, int item)
{

Dr. Nataraju A B Page - 3


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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

Dr. Nataraju A B Page - 4


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

20 enqueued to queue
30 enqueued to queue
40 enqueued to queue
10 dequeued from queue
Front item is 20
Rear item is 40

Advantages of Array Implementation:


 Easy to implement.
 A large amount of data can be managed efficiently with ease.
 Operations such as insertion and deletion can be performed with ease as it follows the first in first out rule.
Disadvantages of Array Implementation:
 Static Data Structure, fixed size.
 If the queue has a large number of enqueue and dequeue operations, at some point (in case of linear increment of front and rear indexes) we may not be able to insert elements in
the queue even if the queue is empty (this problem is avoided by using circular queue).
 Maximum size of a queue must be defined prior.

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.

What is a Linked List?

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 Lists vs Arrays

Here’s the comparison of Linked List vs Arrays

Linked List:

Data Structure: Non-contiguous

Memory Allocation: Dynamic

Insertion/Deletion: Efficient

Dr. Nataraju A B Page - 5


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Access: Sequential

Array:

Data Structure: Contiguous

Memory Allocation: Static

Insertion/Deletion: Inefficient

Access: Random

Following program gives an example implementation of Linked List…


#include <stdio.h>
#include <stdlib.h>
// Node structure
struct Node {
int data;
struct Node* next;
};
// Function to create a new node
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// Function to insert a node at the beginning
void insertAtBeginning(struct Node** head, int data) {
struct Node* newNode = createNode(data);
newNode->next = *head;
*head = newNode;
}
// Function to insert a node at the end
void insertAtEnd(struct Node** head, int data) {
struct Node* newNode = createNode(data);
// empty list…add new one as head of LL
if (*head == NULL) {
*head = newNode;
return;
}
struct Node* temp = *head;
// traverse till end and then add the new element @ end
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
// Function to delete a node with a given key
void deleteNode(struct Node** head, int key) {
struct Node* temp = *head;
struct Node* prev = NULL;
// If head node itself holds the key

Dr. Nataraju A B Page - 6


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

if (temp != NULL && temp->data == key) {


*head = temp->next;
free(temp);
return;
}
// Search for the key
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
// If key was not present in list
if (temp == NULL)
return;
// Unlink the node from linked list
prev->next = temp->next;
free(temp);
}
// Function to search for a node with a given key
int search(struct Node* head, int key) {
struct Node* current = head;
while (current != NULL) {
if (current->data == key) {
return 1; // Key found
}
current = current->next;
}
return 0; // Key not found
}
// Function to traverse and print the linked list
void traverse(struct Node* head) {
struct Node* temp = head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}
// Driver Code
int main() {
struct Node* head = NULL;
// Insertion
insertAtEnd(&head, 10);
insertAtEnd(&head, 20);
insertAtEnd(&head, 30);
insertAtBeginning(&head, 5);
printf("Linked List after insertions: ");
traverse(head);

Dr. Nataraju A B Page - 7


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

// 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.

Dr. Nataraju A B Page - 8


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Other Lists structures – Circular Lists, Stacks,

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.

What is a Circular Linked List?

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

to the next node in the sequence.

Circular Linked List

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.

How to Create a Circular Linked List in C?

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

the first node (also called the head).

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;

Dr. Nataraju A B Page - 9


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

}
*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) {

Dr. Nataraju A B Page - 10


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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

List Before Deletion: 10 8 7 5 2

List After Deletion: 10 8 5 2

Advantages of Circular Linked Lists:


 Any node can be a starting point. We can traverse the whole list by starting from any point. We just need to stop when the first visited node is visited again.
 Useful for implementation of a queue. Unlike this implementation, we don’t need to maintain two pointers for front and rear if we use a circular linked list. We can maintain a

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.

Disadvantages of circular linked list:


 Compared to singly linked lists, circular lists are more complex.
 Reversing a circular list is more complicated than singly or doubly reversing a circular list.
 It is possible for the code to go into an infinite loop if it is not handled carefully.
 It is harder to find the end of the list and control the loop.
 Although circular linked lists can be efficient in certain applications, their performance can be slower than other data structures in certain cases, such as when the list needs to

be sorted or searched.
 Circular linked lists don’t provide direct access to individual nodes

Dr. Nataraju A B Page - 11


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Applications of circular linked lists:


 Multiplayer games use this to give each player a chance to play.
 A circular linked list can be used to organize multiple running applications on an operating system. These applications are iterated over by the OS.
 Circular linked lists can be used in resource allocation problems.
 Circular linked lists are commonly used to implement circular buffers,
 Circular linked lists can be used in simulation and gaming.

Why circular linked list?


 A node always points to another node, so NULL assignment is not necessary.
 Any node can be set as the starting point.
 Nodes are traversed quickly from the first to the last.

Queues as circular list.

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.

What is a Circular 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: How Does It Operate?

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

position to create a circle.

Operations in the circular queue are:

Dr. Nataraju A B Page - 12


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Front – used to obtain the circular queue’s first component.

Rear – used to obtain the circular queue’s last component.

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.

Implementing Queue Operations

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 1: Determine if the queue is full by checking (Rear + 1 % Maxsize = Front).

 Step 2: If the queue is full, an Overflow error will appear.

 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 5: If not, make Rear equal to (Rear + 1)% Maxsize.

 Step 6: Add the element (Queue[Rear] = x) to the queue.

 Step 7: End

Dr. Nataraju A B Page - 13


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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 2: When the queue is empty, a mistake in the underflow

 Step 3: Set Element = Queue[Front]

 Step 4: Set Front and Rear to -1 (IF Front = Rear, set Front = Rear = -1) if a queue only has one element.

 Step 5: And set Front to 0 if Front = Maxsize -1.

 Step 6: If not, change Front to Front + 1.

 Step 7: End

Dr. Nataraju A B Page - 14


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Implementation of Circular Queue using Linked List

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;
}

Dr. Nataraju A B Page - 15


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

else // // add an element into non-empty CQ


{
rear->next=newnode;
rear=newnode;
rear->next=front;
}
}
// function to delete the element from the queue
void dequeue()
{
struct node *temp;
temp=front;
if((front==-1)&&(rear==-1))
{
printf("\nQueue is empty");
}
else if(front==rear) // only one element in CQ
{
front=rear=-1;
free(temp);
}
else // delete an element in CQ with more than one element
{
front=front->next;
rear->next=front;
free(temp);
}
}
// function to get the front of the queue -- front and rear pointers wont be updated… only front element is
returned to calling function.
int peek()
{
if((front==-1) &&(rear==-1))
{
printf("\nQueue is empty");
}
else
{
printf("\nThe front element is %d", front->data);
}

Dr. Nataraju A B Page - 16


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

}
// 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();
}

The Josephus problem,

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.

Dr. Nataraju A B Page - 17


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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 :

Josephus( list , start , k){

if list.size = 1

return list[0]

start = (start + k) % list.size

list.remove( start )

return Josephus( list, start, k)

Approach to solve Josephus problem iteratively:

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)

Dr. Nataraju A B Page - 18


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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.

And counting starts from here.

Dr. Nataraju A B Page - 19


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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.

Dr. Nataraju A B Page - 20


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

Following Fig visualize with K = 3

/*
* 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);

Dr. Nataraju A B Page - 21


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

survive = survivor(&head, skip);


printf("The person to survive is : %d\n", survive);
free(head);
return 0;
}
int survivor(struct node **head, int k)
{
struct node *p, *q;
int i;
q = p = *head;
// repeat till all the elements are visited
while (p->next != p)
{
for (i = 0; i < k - 1; i++)
{
q = p;
p = p->next;
}
q->next = p->next;
printf("%d has been killed.\n", p->num);
free(p);
p = q->next;
}
*head = p;
return (p->num);
}
// create a circular list of elements to solve Josephus problem
void create (struct node **head)
{
struct node *temp, *rear;
int a, ch;
do
{
printf("Enter a number: ");
scanf("%d", &a);
temp = (struct node *)malloc(sizeof(struct node));
temp->num = a;
temp->next = NULL;
if (*head == NULL)
{
*head = temp;
}
else
{
rear->next = temp;
}
rear = temp;

Dr. Nataraju A B Page - 22


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

printf("Do you want to add a number [1/0]? ");


scanf("%d", &ch);
} while (ch != 0);
rear->next = *head;
}
// display the elements in the circular list…
void display(struct node *head)
{
struct node *temp;
temp = head;
printf("%d ", temp->num);
temp = temp->next;
while (head != temp)
{
printf("%d ", temp->num);
temp = temp->next;
}
printf("\n");
}

Doubly linked lists.

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.

Dr. Nataraju A B Page - 23


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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:-

Operation Description Time Complexity Space Complexity

Adding an element to the beginning of the


Insert_at_head O(1) O(1)
doubly linked list.

Deleting an element from the beginning of the


Delete_at_head O(1) O(1)
doubly linked list.

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).

To display the entire doubly linked list in a for-


Display forward O(N) O(1)
ward manner.

To display the entire doubly linked list in a


Display backwards O(N) O(1)
backward manner.

// C Program to illustrate how to create a doubly linked list


#include <stdio.h>
#include <stdlib.h>
// doubly linked list node template
struct node {
int data;
struct node* next;
struct node* prev;
};
// Creating a pointer to head and tail of the linked list
struct node* head = NULL;
struct node* tail = NULL;
// create a new node with the given data and return a pointer to it
struct node* create_node(int data)
{
struct node* new_node

Dr. Nataraju A B Page - 24


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

= (struct node*)malloc(sizeof(struct node));


new_node->data = data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// insert a node at the beginning of the list
void insert_at_head(int data)
{
struct node* new_node = create_node(data);
if (head == NULL) { // empty DLL before insertion
head = new_node;
tail = new_node;
}
else { // non-empty DLL, make new node as head and adjust pointers
new_node->next = head;
head->prev = new_node;
head = new_node;
}
}
// insert a node at the end of the list
void insert_at_tail(int data)
{
struct node* new_node = create_node(data);
if (tail == NULL) // empty DLL before insertion
{
head = new_node;
tail = new_node;
}
else // non-empty DLL, make new node as head and adjust pointers
{
new_node->prev = tail;
tail->next = new_node;
tail = new_node;
}
}
// delete the node at the beginning of the list
void delete_at_head()
{
if (head == NULL) { // empty DLL
return;
}
struct node* temp = head;
if (head == tail) { // only one element in DLL
head = NULL;
tail = NULL;
}

Dr. Nataraju A B Page - 25


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

else { // more than one element in DLL


head = head->next;
head->prev = NULL;
}
free(temp); // delete the node
}
// delete the node at the end of the list
void delete_at_tail()
{
if (tail == NULL) { // empty DLL
return;
}
struct node* temp = tail;
if (head == tail) { // DLL with one element
head = NULL;
tail = NULL;
}
else { // DLL with more than one element
tail = tail->prev;
tail->next = NULL;
}
free(temp); // delete the memory
}
// display the list in forward direction
void display_forward()
{
struct node* current = head; // start traverse from head
while (current != NULL) { // traverse through list – use next pointer
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// display the list in backward direction
void display_backward()
{
struct node* current = tail; // start traverse from tail
while (current != NULL) { // traverse through list – use prev pointer
printf("%d ", current->data);
current = current->prev;
}
printf("\n");
}
// Driver code to test the doubly linked list
int main()
{
insert_at_head(10);

Dr. Nataraju A B Page - 26


Data Structures using C [BEC405D] Dept of ECE, ACIT, Bangalore

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;
}

Linked lists and Queues

Dr. Nataraju A B Page - 27

You might also like