My_Manual
My_Manual
Lab Manual
Data Structures
COMP2117
Submitted By
Name: Abdul Rehman
Roll#: bsf23003501
List of Experiments
Lab
Lab Title Page
No.
Lab # 1 Array 3
Lab # 2 Stack 6
Lab # 8 Queue 17
Array
An array is a fundamental data structure in programming and algorithms, designed to store
elements of the same type in contiguous memory locations. Arrays are extensively used due to
their simplicity and efficiency in accessing elements using indices. Below are essential array
operations and their implementations:
Basic Array Operations
1. Traversal
Description: Access and process each element in the array sequentially.
Time Complexity: O(n)O(n)O(n)
Code:
Input: Output:
#include <iostream> Enter the size of the array: 3
Enter 3 elements:
using namespace std; 123
int main() { The elements of the array are: 1 2 3
int n;
cout << "Enter the size of the array: ";
cin >> n;
int arr[n];
cout << "Enter " << n << " elements:" <<
endl;
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
cout << "The elements of the array are: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
4
2. Insertion
Description: Add a new element at a specific position in the array.
Time Complexity:
o O(1)O(1)O(1) for appending.
o O(n)O(n)O(n) for insertion at any other position (due to shifting elements).
Code:
Input: Output:
#include <iostream> Enter the size of the array: 3
Enter 3 elements: 1
using namespace std; 2
int main() { 3
Enter the position to insert the element: 2
int n, pos, value; Enter the value to insert: 4
Array after insertion: 1 2 4 3
cout << "Enter the size of the array: ";
cin >> n;
int arr[n + 1];
cout << "Enter " << n << " elements: ";
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
cout << "Enter the position to insert the
element: ";
cin >> pos;
cout << "Enter the value to insert: ";
cin >> value;
for (int i = n; i > pos; i--) {
arr[i] = arr[i - 1];
5
}
arr[pos] = value;
n++;
cout << "Array after insertion: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
3. Deletion
Description: Remove an element from a specified position in the array.
Time Complexity: O(n)O(n)O(n) (due to shifting elements).
Code:
Input: Output:
#include <iostream> Enter the size of the array: 3
Enter 3 elements: 1 2 3
using namespace std; Enter the position to delete the element: 0
int main() { Array after deletion: 2 3
int n, pos;
cout << "Enter the size of the array: ";
cin >> n;
int arr[n];
cout << "Enter " << n << " elements: ";
for (int i = 0; i < n; i++) {
cin >> arr[i];
6
}
cout << "Enter the position to delete the
element: ";
cin >> pos;
for (int i = pos; i < n - 1; i++) {
arr[i] = arr[i + 1];
}
n--;
cout << "Array after deletion: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
Stack
A stack is a linear data structure that follows the LIFO (Last In, First Out) principle, meaning the
last element added is the first to be removed.
Key Operations
1. Push: Add an element to the top of the stack.
2. Pop: Remove and return the top element.
3. Peek/Top: View the top element without removing it.
4. isEmpty: Check if the stack is empty.
Code for Stack using Array
Input: Output:
#include <iostream> Top element: 30
Popped element: 30
7
class Stack {
int* arr;
int top;
int capacity;
public:
Stack(int size) {
arr = new int[size];
capacity = size;
top = -1;
}
int pop() {
if (top == -1) {
cout << "Stack Underflow" << endl;
return -1;
}
8
return arr[top--];
}
int peek() {
if (top == -1) {
cout << "Stack is empty" << endl;
return -1;
}
return arr[top];
}
bool isEmpty() {
return top == -1;
}
~Stack() {
delete[] arr;
}
};
int main() {
Stack stack(5);
stack.push(10);
stack.push(20);
stack.push(30);
cout << "Top element: " << stack.peek() <<
endl;
9
Linear Search
Definition: A simple search algorithm that checks every element in the list sequentially
until the desired element is found or the list ends.
Characteristics:
o Does not require the array to be sorted.
o Suitable for small datasets.
o Time Complexity:
Best Case: O(1) (if the element is at the beginning).
Worst Case: O(n) (if the element is at the end or not present).
Code:
Input: Output:
#include <iostream> Element 45 found at index 2
using namespace std;
key is found
}
}
return -1; // Return -1 if the key is not
found
}
int main() {
int arr[] = {10, 23, 45, 70, 11, 15};
int n = sizeof(arr) / sizeof(arr[0]);
int key = 45;
if (result != -1) {
cout << "Element " << key << " found at
index " << result << endl;
} else {
cout << "Element " << key << " not
found." << endl;
}
return 0;
}
11
Binary Search
Definition: A highly efficient search algorithm that repeatedly divides the search interval
in half. Works only on sorted arrays.
Characteristics:
o Requires the array to be sorted in ascending or descending order.
o Time Complexity:
Best Case: O(1) (when the middle element is the target).
Worst and Average Case: O(log n).
Code:
Input: Output:
#include <iostream> Element 10 found at index 3
using namespace std;
else {
left = mid + 1;
}
}
return -1; // Return -1 if the key is not
found
}
int main() {
int arr[] = {2, 3, 4, 10, 40};
int n = sizeof(arr) / sizeof(arr[0]);
int key = 10;
if (result != -1) {
cout << "Element " << key << " found at
index " << result << endl;
} else {
cout << "Element " << key << " not
found." << endl;
}
return 0;
}
13
Sorting Algorithms
1. Bubble Sort
Description: Compare adjacent elements and swap them if they're out of order. Repeat
until the array is sorted.
Time Complexity: O(n2)O(n^2)O(n2)
Code:
Input: Output:
#include <iostream> Enter the size of the array: 4
Enter 4 elements: 2 5 1 3
using namespace std; Sorted array: 1 2 3 5
int main() {
int n;
cout << "Enter the size of the array: ";
cin >> n;
int arr[n];
cout << "Enter " << n << " elements: ";
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
}
}
}
cout << "Sorted array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
14
}
cout << endl;
return 0;
}
2. Selection Sort
Divides the array into a sorted and an unsorted region.
Repeatedly selects the smallest element from the unsorted region and moves it to the
sorted region.
Time Complexity: O(n²).
Code:
Input: Output:
#include <iostream> Sorted array: 10 13 14 29 37
using namespace std;
int main() {
int arr[] = {29, 10, 14, 37, 13};
int n = sizeof(arr) / sizeof(arr[0]);
selectionSort(arr, n);
cout << "Sorted array: ";
displayArray(arr, n);
return 0;
}
3. Insertion Sort
Builds the sorted list one element at a time by comparing the current element to the
already sorted portion.
Time Complexity: O(n²) for the worst case, O(n) for nearly sorted arrays.
Code:
Input: Output:
#include <iostream> Sorted array: 5 6 11 12 13
using namespace std;
16
int main() {
int arr[] = {12, 11, 13, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);
insertionSort(arr, n);
cout << "Sorted array: ";
displayArray(arr, n);
return 0;
17
Queue
A queue is a linear data structure that follows the FIFO (First In, First Out) principle, meaning
the first element added is the first to be removed.
Key Operations
1. Enqueue: Add an element to the rear of the queue.
2. Dequeue: Remove and return the front element.
3. Peek/Front: View the front element without removing it.
4. isEmpty: Check if the queue is empty.
Code for Queue using Array
Input: Output:
#include <iostream> Front element: 10
Front element after dequeue: 20
using namespace std;
class Queue {
int* arr;
int front, rear, capacity;
public:
Queue(int size) {
arr = new int[size];
capacity = size;
front = rear = -1;
}
if (rear == capacity - 1) {
cout << "Queue Overflow" << endl;
return;
}
if (front == -1) front = 0;
arr[++rear] = value;
}
int dequeue() {
if (front == -1 || front > rear) {
cout << "Queue Underflow" << endl;
return -1;
}
return arr[front++];
}
int peek() {
if (front == -1 || front > rear) {
cout << "Queue is empty" << endl;
return -1;
}
return arr[front];
}
bool isEmpty() {
return front == -1 || front > rear;
}
19
~Queue() {
delete[] arr;
}
};
int main() {
Queue queue(5);
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
cout << "Front element: " << queue.peek()
<< endl;
queue.dequeue();
cout << "Front element after dequeue: " <<
queue.peek() << endl;
return 0;
}
Circular Queue
A circular queue is an advanced version of a linear queue where the last position connects back
to the first. This connection makes it efficient in utilizing memory and handling operations
seamlessly in fixed-sized storage.
Key Characteristics of Circular Queue
1. Circular Connection:
20
o The rear wraps around to the front when it reaches the end, enabling continuous
usage of space.
2. Efficient Memory Utilization:
o It avoids leaving unused spaces in the queue after dequeuing.
3. Index Management:
o Positions are handled using modular arithmetic:
rear = (rear + 1) % size
front = (front + 1) % size
Basic Operations
Enqueue: Add an element to the rear of the queue.
Dequeue: Remove an element from the front.
Peek/Front: Retrieve the element at the front without removing it.
isEmpty: Check if the queue is empty.
isFull: Check if the queue is full.
Code for Circular Queue
Input: Output:
#include <iostream> Front element: 10
Front element after dequeue: 20
using namespace std; Is queue full: Yes
class CircularQueue { Dequeue: 20
Dequeue: 30
int *arr; Dequeue: 40
Dequeue: 50
int front, rear, size, capacity;
Dequeue: 60
public: Is queue empty: Yes
CircularQueue(int cap) {
capacity = cap;
arr = new int[capacity];
front = -1;
rear = -1;
21
size = 0;
}
bool isEmpty() {
return size == 0;
}
bool isFull() {
return size == capacity;
}
void enqueue(int value) {
if (isFull()) {
cout << "Queue Overflow" << endl;
return;
}
if (front == -1) front = 0;
rear = (rear + 1) % capacity;
arr[rear] = value;
size++;
}
int dequeue() {
if (isEmpty()) {
cout << "Queue Underflow" << endl;
return -1;
}
int result = arr[front];
front = (front + 1) % capacity;
size--;
return result;
22
}
int peek() {
if (isEmpty()) {
cout << "Queue is empty" << endl;
return -1;
}
return arr[front];
}
~CircularQueue() {
delete[] arr;
}
};
int main() {
CircularQueue cq(5);
cq.enqueue(10);
cq.enqueue(20);
cq.enqueue(30);
cout << "Front element: " << cq.peek() <<
endl;
cq.dequeue();
cout << "Front element after dequeue: " <<
cq.peek() << endl;
cq.enqueue(40);
cq.enqueue(50);
cq.enqueue(60);
cout << "Is queue full: " << (cq.isFull() ?
"Yes" : "No") << endl;
while (!cq.isEmpty())
23
Operations:
1. Insertion:
o At the beginning.
o At the end.
o At a specific position.
2. Deletion:
o From the beginning.
o From the end.
o A specific node by key.
3. Traversal:
o Traverse the list to print elements or perform operations on them.
Code:
Input: Output:
10 -> 20 -> 30 -> NULL
24
// Node structure
struct Node {
int data;
Node* next;
};
if (head == NULL) {
head = newNode;
return;
25
prev->next = temp->next;
delete temp;
}
insertAtBeginning(head, 10);
insertAtEnd(head, 20);
insertAtEnd(head, 30);
displayList(head);
deleteNode(head, 20);
displayList(head);
27
return 0;
}
Sorting Techniques
1. Bubble Sort
Simple sorting algorithm that repeatedly steps through the list, compares adjacent
elements, and swaps them if they are in the wrong order.
Time Complexity: O(n²) for worst and average cases.
Code Implementation:
cpp
Copy code
#include <iostream>
using namespace std;
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
cout << "Sorted array: ";
displayArray(arr, n);
return 0;
}
int data;
Node* next;
Node* prev;
Node(int value) {
data = value;
next = nullptr;
prev = nullptr;
}
};
Operations on Doubly Linked List
1. Insertion
o At the beginning, end, or any given position.
2. Deletion
o From the beginning, end, or a specific position.
3. Traversal
o Forward and backward.
Code for DLL
Input: Output:
#include <iostream> 10 20 30
30 20 10
using namespace std; 10 20
struct Node {
int data;
Node* next;
Node* prev;
30
Node(int value) {
data = value;
next = nullptr;
prev = nullptr;
}
};
class DoublyLinkedList {
Node* head;
public:
DoublyLinkedList() {
head = nullptr;
}
void deleteAtEnd() {
if (!head) {
cout << "List is empty" << endl;
return;
}
if (!head->next) {
delete head;
head = nullptr;
return;
}
Node* temp = head;
while (temp->next)
temp = temp->next;
temp->prev->next = nullptr;
delete temp;
}
void displayForward() {
Node* temp = head;
while (temp) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
void displayBackward() {
if (!head) return;
32