0% found this document useful (0 votes)
11 views30 pages

Dsc-Module II

The document provides an overview of queues and lists as linear data structures, explaining the FIFO principle of queues, their operations, types, and applications. It also details the characteristics and operations of array-based lists and linked lists, including singly and doubly linked lists. Additionally, it includes C code implementations for queues using both arrays and pointers, as well as examples of array-based lists.

Uploaded by

SAI ARAVIND
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)
11 views30 pages

Dsc-Module II

The document provides an overview of queues and lists as linear data structures, explaining the FIFO principle of queues, their operations, types, and applications. It also details the characteristics and operations of array-based lists and linked lists, including singly and doubly linked lists. Additionally, it includes C code implementations for queues using both arrays and pointers, as well as examples of array-based lists.

Uploaded by

SAI ARAVIND
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/ 30

Module II

QUEUES AND LISTS

Queue is a linear data structure that follows FIFO (First In First Out) Principle, so the
first element inserted is the first to be popped out.
FIFO Principle in Queue:
FIFO Principle states that the first element added to the Queue will be the first one to be
removed or processed. So, Queue is like a line of people waiting to purchase tickets, where
the first person in line is the first person served. (i.e. First Come First Serve).

Basic Terminologies of Queue


 Front: Position of the entry in a queue ready to be served, that is, the first entry that
will be removed from the queue, is called the front of the queue. It is also referred as
the head of the queue.
 Rear: Position of the last entry in the queue, that is, the one most recently added, is
called the rear of the queue. It is also referred as the tail of the queue.
 Size: Size refers to the current number of elements in the queue.
 Capacity: Capacity refers to the maximum number of elements the queue can hold.

Representation of Queue

Operations on Queue

1. Enqueue: Enqueue operation adds (or stores) an element to the end of the queue.
Steps:
1. Check if the queue is full. If so, return an overflow error and exit.
2. If the queue is not full, increment the rear pointer to the next available position.
3. Insert the element at the rear.

2.Dequeue: Dequeue operation removes the element at the front of the queue. The
following steps are taken to perform the dequeue operation:
1. Check if the queue is empty. If so, return an underflow error.
2. Remove the element at the front.
3. Increment the front pointer to the next element.

3. Peek or Front Operation:


This operation returns the element at the front end without removing it.
4. Size Operation:
This operation returns the numbers of elements present in the queue.

5. isEmpty Operation:
This operation returns a boolean value that indicates whether the queue is empty or not.

6. isFull Operation:
This operation returns a boolean value that indicates whether the queue is full or not.

Types of Queues

1. Simple Queue: Simple Queue simply follows FIFO Structure. We can only insert the
element at the back and remove the element from the front of the queue.

2. Double-Ended Queue (Deque) : In a double-ended queue the insertion and deletion


operations, both can be performed from both ends.

They are of two types:


 Input Restricted Queue: This is a simple queue. In this type of queue, the input
can be taken from only one end but deletion can be done from any of the ends.
 Output Restricted Queue: This is also a simple queue. In this type of queue, the
input can be taken from both ends but deletion can be done from only one end.

3. Circular Queue: This is a special type of queue where the last position is connected
back to the first position. Here also the operations are performed in FIFO order.

4. Priority Queue: A priority queue is a special queue where the elements are accessed
based on the priority assigned to them. They are of two types:
 Ascending Priority Queue: In Ascending Priority Queue, the elements are
arranged in increasing order of their priority values. Element with smallest priority
value is popped first.
 Descending Priority Queue: In Descending Priority Queue, the elements are
arranged in decreasing order of their priority values. Element with largest priority is
popped first.

Applications of Queue Data Structure


 A Queue is always used as a buffer when we have a speed mismatch between a
producer and consumer.
For example keyboard and CPU.
 Queue can be used where we have a single resource and multiple consumers like a
single CPU and multiple processes.
 In a network, a queue is used in devices such as a router/switch and mail queue.
 Queue can be used in various algorithm techniques like Breadth First Search,
Topological Sort, etc.
 Queues are used in operating systems for process scheduling .
 In printing systems Queues are used to maintain First In First Out(FIFO) order.
 Queues are used in Graph data structures to perform Depth First Search(DFS) .
 Queues are used in databases for transaction processing.

Implementation of queues using arrays in c :


#include <stdio.h>
#include <stdlib.h>
#define MAX 5 // Define the maximum size of the queue
// Queue structure
struct Queue
{
int arr[MAX]; // Array to store the queue elements
int front; // Index for the front of the queue
int rear; // Index for the rear of the queue
};
// Function to initialize the queue
void initQueue(struct Queue* q)
{
q->front = -1;
q->rear = -1;
}

// Function to check if the queue is full


int isFull(struct Queue* q)
{
if (q->rear == MAX - 1)
{
return 1; // Queue is full
}
return 0; // Queue is not full
}
// Function to check if the queue is empty
int isEmpty(struct Queue* q)
{
if (q->front == -1 || q->front > q->rear)
{
return 1; // Queue is empty
}
return 0; // Queue is not empty
}
// Function to enqueue (insert) an element into the queue
void enqueue(struct Queue* q, int value)
{
if (isFull(q))
{
printf("Queue is full! Cannot enqueue %d\n", value);
} else
{
if (q->front == -1)
{
q->front = 0; // If queue is empty, set front to 0
}
q->rear++;
q->arr[q->rear] = value; // Insert element at rear
printf("%d enqueued to the queue\n", value);
}
}
// Function to dequeue (remove) an element from the queue
int dequeue(struct Queue* q)
{
if (isEmpty(q))
{
printf("Queue is empty! Cannot dequeue\n");
return -1; // Indicating the queue is empty
} else
{
int dequeuedValue = q->arr[q->front];
q->front++; // Move front pointer forward
if (q->front > q->rear)
{
q->front = q->rear = -1; // Reset the queue if it becomes empty
}
return dequeuedValue; // Return the dequeued value
}
}
// Function to display the elements of the queue
void display(struct Queue* q)
{
if (isEmpty(q))
{
printf("Queue is empty!\n");
} else
{
printf("Queue elements: ");
for (int i = q->front; i <= q->rear; i++)
{
printf("%d ", q->arr[i]);
}
printf("\n");
}
}
// Main function to test the queue operations
int main()
{
struct Queue q; // Declare a queue
initQueue(&q); // Initialize the queue
// Test the queue operations
enqueue(&q, 10); // Enqueue 10
enqueue(&q, 20); // Enqueue 20
enqueue(&q, 30); // Enqueue 30
enqueue(&q, 40); // Enqueue 40
enqueue(&q, 50); // Enqueue 50
enqueue(&q, 60); // Try to enqueue when the queue is full

display(&q); // Display the queue

printf("Dequeued: %d\n", dequeue(&q)); // Dequeue an element


display(&q); // Display the queue again

printf("Dequeued: %d\n", dequeue(&q)); // Dequeue another element


display(&q); // Display the queue again

return 0;
}

Implementation of queues using pointers in c


#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};

struct Queue
{
struct Node* front;
struct Node* rear;
};

void initializeQueue(struct Queue* q)


{
q->front = NULL;
q->rear = NULL;
}

int isEmpty(struct Queue* q)


{
return (q->front == NULL);
}

void enqueue(struct Queue* q, int value)


{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;
if (isEmpty(q))
{
q->front = newNode;
q->rear = newNode;
}
Else
{
q->rear->next = newNode;
q->rear = newNode;
}
printf("%d enqueued to the queue\n", value);
}
int dequeue(struct Queue* q)
{
if (isEmpty(q))
{
printf("Queue is empty, cannot dequeue\n");
return -1;
}
struct Node* temp = q->front;
int dequeuedValue = temp->data;
q->front = q->front->next;
if (q->front == NULL)
{
q->rear = NULL;
}
free(temp);
printf("%d dequeued from the queue\n", dequeuedValue);
return dequeuedValue;
}

int front(struct Queue* q)


{
if (isEmpty(q))
{
printf("Queue is empty, no front element\n");
return -1;
}
return q->front->data;
}
void displayQueue(struct Queue* q)
{
if (isEmpty(q))
{
printf("Queue is empty\n");
return;
}
struct Node* temp = q->front;
printf("Queue: ");
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main()
{
struct Queue q;
initializeQueue(&q);
enqueue(&q, 10);
enqueue(&q, 20);
enqueue(&q, 30);

displayQueue(&q);
dequeue(&q);
dequeue(&q);
displayQueue(&q);
printf("Front element is: %d\n", front(&q));
return 0;
}

LISTS
In data structures, a list is an ordered collection of elements, where each element is referred
to as a node. Lists can be used to store multiple items in a specific order, and they allow
various operations like insertion, deletion, and traversal.

There are two primary types of lists in data structures:

1. Array-based Lists (Static Lists)


2. Linked Lists (Dynamic Lists)
1. Array-based Lists (Static Lists)
An array-based list uses an array to store elements in contiguous memory locations. In this
implementation, the size of the list is fixed, meaning you need to specify the size of the array
at the time of creation. The elements are indexed, allowing fast access to elements by index.

Characteristics:
 Fixed Size: Once an array is created, its size cannot be changed.
 Random Access: Allows access to any element in constant time using the index.
 Contiguous Memory Allocation: The elements are stored next to each other in
memory.

Operations:
 Insert: Inserting elements may require shifting existing elements if inserting in the
middle or at the beginning.
 Delete: Deleting an element may also require shifting the remaining elements.
 Access: Accessing elements by index is done in constant time, O(1).

Example of Array-based List:

#include <stdio.h>
#define MAX 5
struct ArrayList {
int arr[MAX];
int size; // Tracks the current number of elements
};
void init(struct ArrayList* list)
{
list->size = 0;
}
void insert(struct ArrayList* list, int value)
{
if (list->size < MAX)
{
list->arr[list->size] = value;
list->size++;
} else
{
printf("List is full!\n");
}
}
void display(struct ArrayList* list)
{
for (int i = 0; i < list->size; i++)
{
printf("%d ", list->arr[i]);
}
printf("\n");
}
int main() {
struct ArrayList list;
init(&list);
insert(&list, 10);
insert(&list, 20);
insert(&list, 30);
insert(&list, 40);
insert(&list, 50);
display(&list); // Output: 10 20 30 40 50
return 0;

2. Linked Lists (Dynamic Lists)


A linked list is a data structure where each element (node) contains two parts:
 Data: The actual data the list stores.
 Next: A pointer/reference to the next node in the list.

Characteristics:
 Dynamic Size: The size of a linked list can grow or shrink dynamically, making it
efficient for memory usage.
 Sequential Access: To access an element, you need to traverse the list from the head
to the desired node.
 No Random Access: Unlike arrays, linked lists do not allow direct access to any
element using an index. You must traverse the list to access a node.

Operations:
 Insert: You can insert elements at the beginning, middle, or end of the list.
 Delete: You can delete an element from the beginning, middle, or end.
 Search: You must traverse the list to find an element.
 Traverse: You can traverse the list starting from the head node.

Applications of Lists:

 Array-based Lists:
o Good for situations where you know the number of elements ahead of time
and need fast access to elements.
o Used in applications like database indexing, heaps, and static buffers.

 Linked Lists:
o Ideal for applications where the size of the list is not known in advance, or the
list will be frequently modified (e.g., insertions and deletions).
o Commonly used in implementing queues, stacks, adjacency lists for graphs,
and various dynamic data structures.

Types of Linked Lists:


Circular doubly linked lists

1. Singly Linked List

In a singly linked list, each node contains two fields:

 Data: The actual data stored in the node.


 Next: A pointer (or reference) to the next node in the list.

The key property of a singly linked list is that it allows traversal in only one direction,
starting from the head (first node) and moving toward the tail (last node). The last node's
next pointer is NULL, indicating the end of the list.

Operations:
 Insert at the beginning, middle, or end.
 Delete from the beginning, middle, or end.
 Search for an element.

Example:
#include <stdio.h>
#include <stdlib.h>
// Define the Node structure
struct Node
{
int data;
struct Node* next;
};
// Function to create a new node
struct Node* createNode(int value)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;
return newNode;
}
// Function to insert at the end
void insertAtEnd(struct Node** head, int value)
{
struct Node* newNode = createNode(value);
if (*head == NULL)
{
*head = newNode;
return;
}
struct Node* temp = *head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = newNode;
}

// Function to display the list


void displayList(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL)
{
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

int main()
{
struct Node* head = NULL;
insertAtEnd(&head, 10);
insertAtEnd(&head, 20);
insertAtEnd(&head, 30);
displayList(head); // Output: 10 -> 20 -> 30 -> NULL
return 0;
}

2. Doubly Linked List

A doubly linked list is similar to a singly linked list, but with a key difference: each node has
two pointers:

 Data: The actual data stored in the node.


 Next: A pointer to the next node.
 Prev: A pointer to the previous node.
This allows two-way traversal, meaning you can traverse the list in both directions (from
head to tail and from tail to head). A doubly linked list provides more flexibility compared to
a singly linked list, but it requires more memory due to the extra pointer.

Operations:
 Insert and Delete at the beginning, middle, or end.
 Traverse both forwards and backwards.

Example:
#include <stdio.h>
#include <stdlib.h>

// Define the structure for the doubly linked list node


struct Node {
int data; // Data to store
struct Node* next; // Pointer to the next node
struct Node* prev; // Pointer to the previous node
};

// Function to create a new node


struct Node* createNode(int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}

// Function to insert at the beginning of the doubly linked list


void insertAtBegin(struct Node** head, int value) {
struct Node* newNode = createNode(value);

if (*head == NULL) { // If the list is empty


*head = newNode;
} else {
newNode->next = *head;
(*head)->prev = newNode;
*head = newNode;
}
}

// Function to insert at the end of the doubly linked list


void insertAtEnd(struct Node** head, int value) {
struct Node* newNode = createNode(value);
struct Node* temp = *head;

if (*head == NULL) { // If the list is empty


*head = newNode;
return;
}
// Traverse to the last node
while (temp->next != NULL) {
temp = temp->next;
}

temp->next = newNode;
newNode->prev = temp;
}

// Function to delete a node by value from the doubly linked list


void deleteNode(struct Node** head, int value) {
struct Node* temp = *head;

// Traverse the list to find the node to delete


while (temp != NULL && temp->data != value) {
temp = temp->next;
}

if (temp == NULL) {
printf("Value %d not found in the list.\n", value);
return; // Node with value not found
}

// If the node to delete is the head


if (*head == temp) {
*head = temp->next;
}

// If the node to delete is not the last node


if (temp->next != NULL) {
temp->next->prev = temp->prev;
}

// If the node to delete is not the first node


if (temp->prev != NULL) {
temp->prev->next = temp->next;
}

free(temp);
printf("Node with value %d deleted.\n", value);
}

// Function to display the doubly linked list (from head to tail)


void displayList(struct Node* head) {
struct Node* temp = head;

if (temp == NULL) {
printf("List is empty.\n");
return;
}
printf("Doubly Linked List (Head to Tail): ");
while (temp != NULL) {
printf("%d <-> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

// Function to display the doubly linked list (from tail to head)


void displayListReverse(struct Node* head) {
struct Node* temp = head;

if (temp == NULL) {
printf("List is empty.\n");
return;
}

// Traverse to the last node


while (temp->next != NULL) {
temp = temp->next;
}

printf("Doubly Linked List (Tail to Head): ");


while (temp != NULL) {
printf("%d <-> ", temp->data);
temp = temp->prev;
}
printf("NULL\n");
}

int main() {
struct Node* head = NULL; // Initialize the head of the list

// Insert elements at the beginning and end of the list


insertAtBegin(&head, 10);
insertAtBegin(&head, 20);
insertAtEnd(&head, 30);
insertAtEnd(&head, 40);

displayList(head); // Display from head to tail


displayListReverse(head); // Display from tail to head

// Delete a node by value


deleteNode(&head, 20);
displayList(head); // Display after deletion
displayListReverse(head); // Display after deletion

return 0;
}
3. Circular Linked List

A circular linked list is a variation of either a singly linked list or a doubly linked list where
the last node's pointer (next in singly, both next and prev in doubly) points back to the first
node instead of NULL. This creates a circular structure.

There are two types of circular linked lists:

 Singly Circular Linked List: The next pointer of the last node points to the first
node.
 Doubly Circular Linked List: The next pointer of the last node points to the first
node, and the prev pointer of the first node points to the last node.

A circular singly linked list allows continuous traversal of the list without needing to check
for a NULL value at the end of the list.

Operations:
 Insert at the beginning, middle, or end.
 Delete from the beginning, middle, or end.
 Traverse continuously.

Example

#include <stdio.h>
#include <stdlib.h>

// Define the structure for a node


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 = newNode; // Points to itself
return newNode;
}

// Function to insert a node at the end of the list


void append(struct Node** head, int data) {
struct Node* newNode = createNode(data);

if (*head == NULL)
{
*head = newNode; // If the list is empty, the new node becomes the head
} else {
struct Node* temp = *head;
// Traverse to the last node (which points to the head)
while (temp->next != *head)
{
temp = temp->next;
}
temp->next = newNode;
newNode->next = *head; // The last node points to the head, forming a circle
}
}

// Function to display the list


void display(struct Node* head)
{
if (head == NULL) {
printf("The list is empty.\n");
return;
}

struct Node* temp = head;


do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != head); // Stop when we circle back to the head
printf("(head)\n");
}

// Function to delete a node by its value


void deleteNode(struct Node** head, int value)
{
if (*head == NULL) {
printf("The list is empty.\n");
return;
}

struct Node* temp = *head;


struct Node* prev = NULL;

// Case 1: The head node itself needs to be deleted


if (temp->data == value)
{
if (temp->next == *head)
{ // If only one node exists
free(temp);
*head = NULL;
} else
{
// Traverse to the last node
while (temp->next != *head)
{
temp = temp->next;
}
temp->next = (*head)->next;
free(*head);
*head = temp->next;
}
return;
}

// Case 2: Node to be deleted is not the head


while (temp->next != *head && temp->data != value) {
prev = temp;
temp = temp->next;
}

if (temp->data == value) {
prev->next = temp->next;
free(temp);
} else {
printf("Node with value %d not found.\n", value);
}
}

// Main function to test the Circular Linked List


int main() {
struct Node* head = NULL;

// Append nodes to the circular linked list


append(&head, 10);
append(&head, 20);
append(&head, 30);
append(&head, 40);

printf("Circular Linked List:\n");


display(head);

// Deleting a node
deleteNode(&head, 20);
printf("\nCircular Linked List after deleting 20:\n");
display(head);

// Deleting the head node


deleteNode(&head, 10);
printf("\nCircular Linked List after deleting head node (10):\n");
display(head);

return 0;
}

4. Circular Doubly Linked List

A circular doubly linked list is a combination of a doubly linked list and a circular linked
list. The next pointer of the last node points to the first node, and the prev pointer of the first
node points to the last node. This allows for continuous two-way traversal.
Operations:

 Insert at the beginning, middle, or end.


 Delete from the beginning, middle, or end.
 Traverse in both directions and continuously.

Example:

struct Node
{
int data;
struct Node* next;
struct Node* prev;
};

Summary of Linked List Types:


Type Direction of Traversal Additional Features

Simple, minimal memory usage. Last


Singly Linked List One direction (head to tail)
node points to NULL.

Both directions (head to tail Extra memory for prev pointer. Allows
Doubly Linked List
and tail to head) easy backward traversal.

Circular Singly One direction (head to tail, The last node points to the first node.
Linked List then back to head) Continuous traversal.

Circular Doubly Both directions (head to tail Both next and prev pointers link the first
Linked List and tail to head) and last nodes.

Advantages:

 Singly Linked List:


o Use when memory usage is a concern and you only need to traverse the list in
one direction.
o Good for simple tasks like queues or stacks.

 Doubly Linked List:


o Use when you need two-way traversal (forward and backward) and are okay
with extra memory overhead.
o Ideal for applications like navigation systems (where you can go forward and
backward), implementing undo/redo functionality, and for managing browser
history.

 Circular Linked List:


o Use when you need continuous traversal and when you don’t want to deal with
the NULL value at the end of the list.
o Common in scenarios like round-robin scheduling or circular buffers.

 Circular Doubly Linked List:


o Use when you need continuous two-way traversal and want to avoid dealing
with the NULL pointer.
o Suitable for complex applications where elements need to be accessed from
both directions in a circular manner.

Searching and Sorting :

1. Searching
Searching algorithms are used to find specific elements within a dataset. The most common
searching algorithms include:

 Linear Search:
o How it works: Iterates through each element in the list and compares it with
the target element.
o Time Complexity: O(n), where n is the number of elements in the list.
o Best for: Small or unsorted datasets.
 Binary Search:
o How it works: Works on sorted datasets by repeatedly dividing the search
interval in half. It compares the target element to the middle element and
eliminates half of the remaining elements from consideration.
o Time Complexity: O(log n), where n is the number of elements in the list.
o Best for: Large, sorted datasets.

2. Sorting

Sorting algorithms arrange elements in a particular order (typically in ascending or


descending order). Some common sorting algorithms include:

 Bubble Sort:
o How it works: Compares adjacent elements and swaps them if they are in the
wrong order. This process repeats until the list is sorted.
o Time Complexity: O(n²).
o Best for: Small datasets or when simplicity is needed.

 Selection Sort:
o How it works: Divides the list into a sorted and unsorted region. It repeatedly
selects the smallest (or largest) element from the unsorted region and swaps it
with the first unsorted element.
o Time Complexity: O(n²).
o Best for: Simple and small datasets.

 Insertion Sort:
o How it works: Builds the final sorted array one element at a time by inserting
elements into their correct position.
o Time Complexity: O(n²) in the worst case, but O(n) in the best case (if the list
is already sorted).
o Best for: Small datasets or nearly sorted datasets.

 Merge Sort:
o How it works: Divides the list into two halves, sorts each half recursively, and
then merges the sorted halves back together.
o Time Complexity: O(n log n).
o Best for: Large datasets that need stable sorting.

 Quick Sort:
o How it works: Selects a pivot element, partitions the list around the pivot, and
recursively sorts the sublists.
o Time Complexity: O(n log n) on average, O(n²) in the worst case (if the pivot
selection is poor).
o Best for: Large datasets with a good average-case performance.

 Heap Sort:
o How it works: Builds a binary heap (either max-heap or min-heap) and
repeatedly extracts the maximum (or minimum) element to build a sorted list.
o Time Complexity: O(n log n).
o Best for: When constant time for finding the maximum/minimum is
important.

When to Use Which:


 Searching:

o Use linear search for small or unsorted datasets.


o Use binary search for large, sorted datasets.

 Sorting:
o Use insertion sort, selection sort, or bubble sort for small datasets or when
simplicity is preferred.
o Use merge sort, quick sort, or heap sort for large datasets requiring efficient
sorting.

// Recursive function to perform linear search

#include <stdio.h>
int linearSearchRecursive(int arr[], int n, int target, int index)
{
// Base case: If the index reaches the size of the array, the target is not found
if (index == n)
{
return -1;
}

// If the element at the current index matches the target, return the index
if (arr[index] == target)
{
return index;
}
// Recur for the next index
return linearSearchRecursive(arr, n, target, index + 1);
}

int main()
{
int n, target, index;
// Input the size of the array
printf("Enter the number of elements: ");
scanf("%d", &n);
// Declare the array
int arr[n];
// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Input the target element to search for


printf("Enter the element to search for: ");
scanf("%d", &target);

// Perform recursive linear search, starting from index 0


index = linearSearchRecursive(arr, n, target, 0);

// Output the result


if (index != -1)
{
printf("Element %d found at index %d.\n", target, index);
} else
{
printf("Element %d not found in the array.\n", target);
}

return 0;
}

// Non-recursive function to perform linear search

#include <stdio.h>
int linearSearch(int arr[], int n, int target) {
// Loop through the array
for (int i = 0; i < n; i++) {
// If the element matches the target, return the index
if (arr[i] == target) {
return i;
}
}
// If element is not found, return -1
return -1;
}
int main() {
int n, target, index;
// Input the size of the array
printf("Enter the number of elements: ");
scanf("%d", &n);
// Declare the array
int arr[n];
// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// Input the target element to search for
printf("Enter the element to search for: ");
scanf("%d", &target);
// Perform non-recursive linear search
index = linearSearch(arr, n, target);
// Output the result
if (index != -1) {
printf("Element %d found at index %d.\n", target, index);
} else {
printf("Element %d not found in the array.\n", target);
}
return 0;
}

// Recursive function to perform binary search

#include <stdio.h>
int binarySearchRecursive(int arr[], int left, int right, int target) {
// Base case: If the right index is greater than or equal to the left index
if (left <= right) {
// Find the middle index
int mid = left + (right - left) / 2;

// If the target is at the middle, return the index


if (arr[mid] == target) {
return mid;
}

// If the target is smaller than the middle element, search in the left half
if (arr[mid] > target) {
return binarySearchRecursive(arr, left, mid - 1, target);
}

// Otherwise, search in the right half


return binarySearchRecursive(arr, mid + 1, right, target);
}

// Return -1 if the target is not found


return -1;
}

int main() {
int n, target, index;

// Input the size of the array


printf("Enter the number of elements: ");
scanf("%d", &n);

// Declare the array


int arr[n];

// Input the elements of the array


printf("Enter the elements in sorted order:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Input the target element to search for


printf("Enter the element to search for: ");
scanf("%d", &target);

// Perform recursive binary search


index = binarySearchRecursive(arr, 0, n - 1, target);

// Output the result


if (index != -1) {
printf("Element %d found at index %d.\n", target, index);
} else {
printf("Element %d not found in the array.\n", target);
}

return 0;
}

// Non-recursive function to perform binary search


#include <stdio.h>
int binarySearch(int arr[], int n, int target) {
int left = 0; // Starting index
int right = n - 1; // Ending index

// Loop while the left index is less than or equal to the right index
while (left <= right) {
int mid = left + (right - left) / 2; // Find the middle index

// If the element at mid is the target, return the mid index


if (arr[mid] == target) {
return mid;
}

// If the target is smaller than the element at mid, search the left half
if (arr[mid] > target) {
right = mid - 1;
}
// Otherwise, search the right half
else {
left = mid + 1;
}
}

// If the target is not found, return -1


return -1;
}

int main() {
int n, target, index;

// Input the size of the array


printf("Enter the number of elements: ");
scanf("%d", &n);

// Declare the array


int arr[n];

// Input the elements of the array


printf("Enter the elements in sorted order:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Input the target element to search for


printf("Enter the element to search for: ");
scanf("%d", &target);

// Perform non-recursive binary search


index = binarySearch(arr, n, target);

// Output the result


if (index != -1) {
printf("Element %d found at index %d.\n", target, index);
} else {
printf("Element %d not found in the array.\n", target);
}

return 0;
}

//Both recursive and non recursive function for linear search in a single program

#include <stdio.h>
// Non-recursive function to perform linear search
int linearSearchNonRecursive(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
return i; // Return index if element is found
}
}
return -1; // Return -1 if element is not found
}
// Recursive function to perform linear search
int linearSearchRecursive(int arr[], int n, int target, int index) {
// Base case: If the index reaches the size of the array, the target is not found
if (index == n) {
return -1;
}

// If the element matches the target, return the index


if (arr[index] == target) {
return index;
}
// Recur for the next element
return linearSearchRecursive(arr, n, target, index + 1);
}

int main() {
int n, target, index, choice;

// Input the size of the array


printf("Enter the number of elements: ");
scanf("%d", &n);
// Declare the array
int arr[n];// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// Input the target element to search for
printf("Enter the element to search for: ");
scanf("%d", &target);
// Ask the user which method to use (recursive or non-recursive)
printf("Choose the search method:\n");
printf("1. Non-recursive\n");
printf("2. Recursive\n");
printf("Enter your choice: ");
scanf("%d", &choice);
if (choice == 1) {
// Perform non-recursive linear search
index = linearSearchNonRecursive(arr, n, target);
if (index != -1) {
printf("Element %d found at index %d (Non-recursive search).\n", target, index);
} else {
printf("Element %d not found in the array (Non-recursive search).\n", target);
}
} else if (choice == 2) {
// Perform recursive linear search
index = linearSearchRecursive(arr, n, target, 0);
if (index != -1) {
printf("Element %d found at index %d (Recursive search).\n", target, index);
} else {
printf("Element %d not found in the array (Recursive search).\n", target);
}
} else {
printf("Invalid choice!\n");
}
return 0;
}

//Both recursive and non recursive function for binary search in a single program
#include <stdio.h>
// Non-recursive function to perform binary search
int binarySearchNonRecursive(int arr[], int n, int target) {
int left = 0;
int right = n - 1;

while (left <= right) {


int mid = left + (right - left) / 2;

// If the element at mid is the target, return the mid index


if (arr[mid] == target) {
return mid;
}

// If the target is smaller than the element at mid, search in the left half
if (arr[mid] > target) {
right = mid - 1;
}
// Otherwise, search in the right half
else {
left = mid + 1;
}
}
// If the target is not found, return -1
return -1;
}

// Recursive function to perform binary search


int binarySearchRecursive(int arr[], int left, int right, int target) {
// Base case: If the right index is greater than or equal to the left index
if (left <= right) {
int mid = left + (right - left) / 2;
// If the element at mid is the target, return the mid index
if (arr[mid] == target) {
return mid;
}

// If the target is smaller than the element at mid, search in the left half
if (arr[mid] > target) {
return binarySearchRecursive(arr, left, mid - 1, target);
}

// Otherwise, search in the right half


return binarySearchRecursive(arr, mid + 1, right, target);
}

// Return -1 if the element is not found


return -1;
}

int main() {
int n, target, index, choice;

// Input the size of the array


printf("Enter the number of elements: ");
scanf("%d", &n);

// Declare the array


int arr[n];

// Input the elements of the array (must be sorted for binary search)
printf("Enter the elements in sorted order:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Input the target element to search for


printf("Enter the element to search for: ");
scanf("%d", &target);

// Ask the user which method to use (recursive or non-recursive)


printf("Choose the search method:\n");
printf("1. Non-recursive\n");
printf("2. Recursive\n");
printf("Enter your choice: ");
scanf("%d", &choice);

if (choice == 1) {
// Perform non-recursive binary search
index = binarySearchNonRecursive(arr, n, target);
if (index != -1) {
printf("Element %d found at index %d (Non-recursive search).\n", target, index);
} else {
printf("Element %d not found in the array (Non-recursive search).\n", target);
}
} else if (choice == 2) {
// Perform recursive binary search
index = binarySearchRecursive(arr, 0, n - 1, target);
if (index != -1) {
printf("Element %d found at index %d (Recursive search).\n", target, index);
} else {
printf("Element %d not found in the array (Recursive search).\n", target);
}
} else {
printf("Invalid choice!\n");
}

return 0;
}

Insertion sort

#include <stdio.h>
// Function to perform Insertion Sort
void insertionSort(int arr[], int n) {
int i, key, j;
// Traverse the array from the second element
for (i = 1; i < n; i++) {
key = arr[i]; // Store the current element to be inserted
j = i - 1;
// Move elements of arr[0..i-1] that are greater than key, one position ahead
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
// Place the key after the last moved element
arr[j + 1] = key;
}
}
// Function to print the array
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

int main() {
int n;
// Input the size of the array
printf("Enter the number of elements: ");
scanf("%d", &n);
int arr[n];
// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// Perform insertion sort
insertionSort(arr, n);
// Print the sorted array
printf("Sorted array: ");
printArray(arr, n);
return 0;
}

//Selection sort

#include <stdio.h>
// Function to perform Selection Sort
void selectionSort(int arr[], int n) {
int i, j, minIdx, temp;
// Traverse through all array elements
for (i = 0; i < n - 1; i++) {
// Find the minimum element in unsorted array
minIdx = i;
for (j = i + 1; j < n; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
// Swap the found minimum element with the element at i
temp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = temp;
}
}

// Function to print the array


void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

int main() {
int n;
// Input the size of the array
printf("Enter the number of elements: ");
scanf("%d", &n);
int arr[n];
// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Perform selection sort


selectionSort(arr, n);
// Print the sorted array
printf("Sorted array: ");
printArray(arr, n);
return 0;
}

//Bubble sort
#include <stdio.h>
// Function to perform Bubble Sort
void bubbleSort(int arr[], int n) {
int i, j, temp;

// Traverse through all array elements


for (i = 0; i < n - 1; i++) {
// Last i elements are already sorted, so no need to check them
for (j = 0; j < n - i - 1; j++) {
// Swap if the element found is greater than the next element
if (arr[j] > arr[j + 1]) {
// Swap the elements
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

// Function to print the array


void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int n;
// Input the size of the array
printf("Enter the number of elements: ");
scanf("%d", &n);
int arr[n];
// Input the elements of the array
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// Perform bubble sort
bubbleSort(arr, n);
// Print the sorted array
printf("Sorted array: ");
printArray(arr, n);
return 0;
}

You might also like