0% found this document useful (0 votes)
7 views45 pages

Data Structure Lab File

The document is a lab file for the Data Structure Lab course at KCC Institute of Technology & Management for the academic year 2025-26. It includes a list of experiments focusing on various data structure implementations, such as sorting techniques (Bubble Sort, Insertion Sort, Selection Sort, Shell Sort, Radix Sort, Quick Sort) and data structures (Stacks, Queues, Linked Lists, Trees, Graphs). Each section provides theoretical background, algorithms, C code implementations, and example outputs.

Uploaded by

phoenix07112002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views45 pages

Data Structure Lab File

The document is a lab file for the Data Structure Lab course at KCC Institute of Technology & Management for the academic year 2025-26. It includes a list of experiments focusing on various data structure implementations, such as sorting techniques (Bubble Sort, Insertion Sort, Selection Sort, Shell Sort, Radix Sort, Quick Sort) and data structures (Stacks, Queues, Linked Lists, Trees, Graphs). Each section provides theoretical background, algorithms, C code implementations, and example outputs.

Uploaded by

phoenix07112002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Department of computer Science & Engineering

KCC INSTITUTE OF TECHNOLOGY & MANAGEMENT


2B-2C, Knowledge Park-III, Greater Noida, Uttar Pradesh

BCS351-DATA STRUCTURE LAB

LAB FILE
(2025-26)
THIRD SEMESTER

SUBMITTED TO:​ SUBMITTED BY:


Satyam Mishra​ Priyanshu Tiwari
(Data Structure Trainer)​ [Link]-CSE(AI) (3rd Sem)
Department of CSE​ Roll No.: 2404921520158
Section: B7
Index
Page
Sr. No. Name of the experiment Date
No.
1.
Implementing Sorting Techniques

2.
Implementing Searching and Hashing Techniques

3.
Implementing Stacks

4.
Implementing Queue

5.
Implementing Linked List

6.
Implementing Trees

7.
Implementing Graphs
Experiment No. -1
< Implementing Sorting Techniques >

(i)To implement Bubble Sort to sort a given list of numbers in


ascending order.

Theory:

Bubble sort is a simple comparison–based sorting algorithm. It repeatedly


compares adjacent elements of the array and swaps them if they are in the wrong
order. In each pass, the largest element “bubbles up” to its correct position at the
end of the array. Time complexity in worst and average case is O(n²).

Algorithm:

●​ Start
●​ Read n, the number of elements.
●​ Read n elements into array a[ ].
●​ Repeat steps 5–7 for i = 0 to n-2
●​ Repeat for j = 0 to n-2-i
●​ If `a[j] > a[j+1]` then swap `a[j]` and `a[j+1]`.
●​​
●​ End inner loop
●​ End outer loop
●​ Display the sorted array.
●​ Stop

PROGRAM CODE(C) :

#include <stdio.h>

int main() {

int a[50];

int n, i, j, temp;

printf("Enter number of elements: ");

scanf("%d", &n);

printf("Enter %d elements:\n", n);

for (i = 0; i < n; i++) {

scanf("%d", &a[i]);

}
for (i = 0; i < n - 1; i++) {

for (j = 0; j < n - 1 - i; j++) {

if (a[j] > a[j + 1]) {

temp = a[j];

a[j] = a[j + 1];

a[j + 1] = temp;

printf("Sorted array (ascending):\n");

for (i = 0; i < n; i++) {

printf("%d ", a[i]);

Return 0;

************************Output*******************************

Result / Conclusion:

Thus the Bubble Sort algorithm was implemented in C language and the given list of numbers was
successfully sorted in ascending order.

Viva-Voce Questions:

1.​ Q: What is the time complexity of bubble sort?


Ans: O(n²) in worst and average case, O(n) in best case (already sorted array).

2.​ Q: Why is it called “Bubble” sort?


Ans: Because in each pass, the largest element moves to the end like a bubble rising to the surface.

3.​ Q: Is bubble sort stable?


Ans: Yes, it is a stable sorting algorithm.
(ii) Insertion Sort:-

Insertion Sort is a simple sorting algorithm that works the way we sort playing cards
in our hands. It builds the final sorted array one item at a time.

●​ It’s efficient for small datasets or when the array is almost sorted.
●​ Time Complexity:
○​ Best case (already sorted): O(n)
○​ Worst case (reverse order): O(n²)
○​ Average case: O(n²)
●​ Space Complexity: O(1) (in-place sorting)

⚙️ Algorithm:-​
1.​ Start from the second element (index 1), because the first element is trivially sorted.
2.​ Compare the current element with the elements before it.
3.​ Shift all larger elements one position ahead to make space.
4.​ Insert the current element into its correct position.
5.​ Repeat until the array is fully sorted.

💻 C Implementation :-
#include <stdio.h>

// Function to perform insertion sort


void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i]; // Current element to be inserted
j = i - 1;

// Shift elements of arr[0..i-1] that are greater than key


while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key; // Insert key at correct position
}
}

// 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 arr[] = {12, 11, 13, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");


printArray(arr, n);

insertionSort(arr, n);
printf("Sorted array: ");
printArray(arr, n);

return 0;
}

Example:-

For array: {12, 11, 13, 5, 6}

●​ Step 1: Compare 11 with 12 → Insert before → {11, 12, 13, 5, 6}


●​ Step 2: 13 is already in correct place → {11, 12, 13, 5, 6}
●​ Step 3: Insert 5 → {5, 11, 12, 13, 6}
●​ Step 4: Insert 6 → {5, 6, 11, 12, 13}
●​ Sorted!

(iii) Selection Sort :-

Selection Sort is a simple comparison-based sorting algorithm. It repeatedly finds


the minimum element from the unsorted part of the array and places it at the beginning.

●​ Works by dividing the array into two parts:


○​ Sorted part (built up from left to right)
○​ Unsorted part (shrinks as sorting progresses)
●​ Time Complexity:
○​ Best case: O(n²)
○​ Worst case: O(n²)
○​ Average case: O(n²)
●​ Space Complexity: O(1) (in-place sorting)

⚙️ Algorithm (Step-by-Step)​
1.​ Start with the first element as the minimum.
2.​ Compare it with the rest of the array to find the smallest element.
3.​ Swap the smallest element with the first element.
4.​ Move to the next position and repeat until the array is sorted.

💻 C Implementation:-
#include <stdio.h>

// Function to perform selection sort

void selectionSort(int arr[], int n) {

int i, j, min_idx, temp;

// Move boundary of unsorted subarray

for (i = 0; i < n-1; i++) {

min_idx = i; // Assume the current index is the minimum


// Find the minimum element in the unsorted array

for (j = i+1; j < n; j++) {

if (arr[j] < arr[min_idx])

min_idx = j;

// Swap the found minimum element with the first element

temp = arr[min_idx];

arr[min_idx] = arr[i];

arr[i] = 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 arr[] = {64, 25, 12, 22, 11};

int n = sizeof(arr)/sizeof(arr[0]);

printf("Original array: ");

printArray(arr, n);

selectionSort(arr, n);

printf("Sorted array: ");

printArray(arr, n);

return 0;

Example:-

For array: {64, 25, 12, 22, 11}

●​ Step 1: Find min (11), swap with 64 → {11, 25, 12, 22, 64}
●​ Step 2: Find min (12), swap with 25 → {11, 12, 25, 22, 64}
●​ Step 3: Find min (22), swap with 25 → {11, 12, 22, 25, 64}
●​ Step 4: Find min (25), already in place → {11, 12, 22, 25, 64}

Sorted!

(iv) Shell Sort:-

●​ Shell Sort is an optimization of Insertion Sort. Instead of comparing adjacent


elements one by one, it compares elements that are far apart (using a gap).
●​ The gap is gradually reduced until it becomes 1, at which point the algorithm
behaves like insertion sort.
●​ This reduces the number of shifts required and makes sorting faster for larger
arrays.

Key Idea:​
Start with a large gap, sort elements that are that far apart, then reduce the gap and
repeat until the gap is 1.

⚙️ Algorithm:-
1.​ Choose an initial gap (commonly n/2).
2.​ Perform a gapped insertion sort:
○​ Compare elements that are gap apart.
○​ Swap them if they are out of order.
3.​ Reduce the gap (usually gap = gap/2).
4.​ Repeat until the gap becomes 0.

💻 C Implementation
#include <stdio.h>

// Function to perform Shell Sort

void shellSort(int arr[], int n) {

// Start with a big gap, then reduce the gap

for (int gap = n/2; gap > 0; gap /= 2) {

// Do a gapped insertion sort for this gap size

for (int i = gap; i < n; i++) {

int temp = arr[i];

int j;

// Shift earlier gap-sorted elements up until correct location found

for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {

arr[j] = arr[j - gap];

arr[j] = 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 arr[] = {12, 34, 54, 2, 3};

int n = sizeof(arr)/sizeof(arr[0]);

printf("Original array: ");

printArray(arr, n);

shellSort(arr, n);

printf("Sorted array: ");

printArray(arr, n);

return 0;

Example:-

For array: {12, 34, 54, 2, 3}

●​ Gap = 2 → Compare elements 2 apart → partially sorted.


●​ Gap = 1 → Normal insertion sort → fully sorted.​
Final result: {2, 3, 12, 34, 54}

(v) Radix Sort:-


Radix Sort is a non-comparative sorting algorithm. It sorts numbers digit by digit, starting
from the least significant digit (LSD) to the most significant digit (MSD) (or vice versa).

●​ It uses a stable subroutine like Counting Sort to sort digits at each position.
●​ Works best when the range of digits is small compared to the number of elements.

Key Idea:​
Sort numbers by their digits, one place at a time, until all digits are processed.​


⚙️ Algorithm:-​
1.​ Find the maximum number to know the number of digits.
2.​ Starting from the least significant digit:
○​ Use Counting Sort to sort numbers based on that digit.
3.​ Move to the next digit and repeat.
4.​ Continue until all digits are sorted.

💻 C Implementation:-
#include <stdio.h>

// Function to get maximum value in arr[]

int getMax(int arr[], int n) {

int max = arr[0];

for (int i = 1; i < n; i++)

if (arr[i] > max)

max = arr[i];

return max;

// A function to do counting sort of arr[] according to the digit represented by exp

void countSort(int arr[], int n, int exp) {

int output[n]; // output array

int count[10] = {0};

// Count occurrences of digits

for (int i = 0; i < n; i++)

count[(arr[i] / exp) % 10]++;

// Change count[i] so that count[i] contains actual position of this digit in output[]

for (int i = 1; i < 10; i++)

count[i] += count[i - 1];

// Build the output array

for (int i = n - 1; i >= 0; i--) {

output[count[(arr[i] / exp) % 10] - 1] = arr[i];

count[(arr[i] / exp) % 10]--;


}

// Copy the output array to arr[]

for (int i = 0; i < n; i++)

arr[i] = output[i];

// Radix Sort function

void radixSort(int arr[], int n) {

int m = getMax(arr, n);

// Do counting sort for every digit

for (int exp = 1; m / exp > 0; exp *= 10)

countSort(arr, n, exp);

// Function to print array

void printArray(int arr[], int n) {

for (int i = 0; i < n; i++)

printf("%d ", arr[i]);

printf("\n");

int main() {

int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};

int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");

printArray(arr, n);

radixSort(arr, n);

printf("Sorted array: ");

printArray(arr, n);

return 0;

Example:-

Original array: 170 45 75 90 802 24 2 66


Sorted array: 2 24 45 66 75 90 170 802

(vi) Quick Sort:-


Quick Sort is a divide-and-conquer sorting algorithm. It works by selecting a pivot element,
then partitioning the array into:

○​ Elements smaller than pivot


○​ Elements greater than pivot
●​ Recursively apply the same process to subarrays until sorted.
●​ Time Complexity:
○​ Best case: O(n log n)
○​ Average case: O(n log n)
○​ Worst case: O(n²) (when pivot is always the smallest/largest element)
●​ Space Complexity: O(log n) (due to recursion stack)

Algorithm:-
1.​ Choose a pivot (commonly the last element).
2.​ Partition the array so that:
○​ All elements smaller than pivot are on the left.
○​ All elements greater than pivot are on the right.
3.​ Recursively apply Quick Sort to left and right subarrays.
4.​ Continue until subarrays have one element (base case).

💻 C Implementation:-
#include <stdio.h>

// Function to swap two elements

void swap(int *a, int *b) {

int temp = *a;

*a = *b;

*b = temp;

int partition(int arr[], int low, int high) {

int pivot = arr[high]; // pivot element

int i = (low - 1); // index of smaller element

for (int j = low; j < high; j++) {

// If current element is smaller than or equal to pivot

if (arr[j] <= pivot) {

i++;

swap(&arr[i], &arr[j]);
}

swap(&arr[i + 1], &arr[high]);

return (i + 1);

void quickSort(int arr[], int low, int high) {

if (low < high) {

int pi = partition(arr, low, high);

quickSort(arr, low, pi - 1);

quickSort(arr, pi + 1, high);

void printArray(int arr[], int size) {

for (int i = 0; i < size; i++)

printf("%d ", arr[i]);

printf("\n");

int main() {

int arr[] = {10, 7, 8, 9, 1, 5};

int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");

printArray(arr, n);

quickSort(arr, 0, n - 1);

printf("Sorted array: ");

printArray(arr, n);

return 0;

Example:-

Original array: 10 7 8 9 1 5

Sorted array: 1 5 7 8 9 10
EXPERIMENT NO. :- 2
(Implementing Searching and Hashing Technique)

Linear Search:-
●​ Linear Search is the simplest searching algorithm. It checks each element of the
array one by one until the desired element is found or the list ends.
●​ Works on both sorted and unsorted arrays.
●​ Time Complexity:
○​ Best case: O(1) (element found at first position)
○​ Worst case: O(n) (element not found or at last position)
○​ Average case: O(n)
●​ Space Complexity: O(1)

⚙️ Algorithm:-​
1.​ Start from the first element of the array.
2.​ Compare the target element with the current element.
3.​ If they match, return the index (position).
4.​ If not, move to the next element.
5.​ Continue until the element is found or the array ends.
6.​ If not found, return -1 (or indicate "not found").

💻 C Implementation:-
#include <stdio.h>

// Function to perform linear search

int linearSearch(int arr[], int n, int key) {

for (int i = 0; i < n; i++) {

if (arr[i] == key)

return i; // return index if found

return -1; // return -1 if not found

int main() {

int arr[] = {10, 20, 30, 40, 50};

int n = sizeof(arr) / sizeof(arr[0]);

int key = 30;

printf("Array elements: ");


for (int i = 0; i < n; i++)

printf("%d ", arr[i]);

printf("\n");

int result = linearSearch(arr, n, key);

if (result != -1)

printf("Element %d found at index %d\n", key, result);

else

printf("Element %d not found in the array\n", key);

return 0;

Example:-

Array elements: 10 20 30 40 50

Element 30 found at index 2

Binary Search:-
Binary Search is a fast searching algorithm used on sorted arrays. It works by repeatedly
dividing the search interval in half:

○​ Compare the target element with the middle element.


○​ If equal → found.
○​ If smaller → search left half.
○​ If larger → search right half.
●​ Time Complexity:
○​ Best case: O(1) (element found at middle)
○​ Worst case: O(log n)
○​ Average case: O(log n)
●​ Space Complexity: O(1) (iterative) or O(log n) (recursive stack)

⚙️ Algorithm:-​
1.​ Start with two pointers: low = 0, high = n-1.
2.​ Find the middle index: mid = (low + high) / 2.
3.​ If arr[mid] == key, return mid.
4.​ If arr[mid] > key, search left half (high = mid - 1).
5.​ If arr[mid] < key, search right half (low = mid + 1).
6.​ Repeat until low > high.
7.​ If not found, return -1.

💻

C Implementation (Iterative):-​
#include <stdio.h>

// Function to perform binary search

int binarySearch(int arr[], int n, int key) {

int low = 0, high = n - 1;

while (low <= high) {

int mid = (low + high) / 2;

if (arr[mid] == key)

return mid; // element found

else if (arr[mid] < key)

low = mid + 1; // search right half

else

high = mid - 1; // search left half

return -1; // element not found

int main() {

int arr[] = {10, 20, 30, 40, 50};

int n = sizeof(arr) / sizeof(arr[0]);

int key = 40;

printf("Array elements: ");

for (int i = 0; i < n; i++)

printf("%d ", arr[i]);

printf("\n");

int result = binarySearch(arr, n, key);

if (result != -1)

printf("Element %d found at index %d\n", key, result);

else

printf("Element %d not found in the array\n", key);

return 0;}
Methods for hashing
Modulo division:-

●​ In hashing, we need a hash function to map a key to an index in the hash table. The
modulo division method is one of the simplest and most widely used hash functions.
●​ Formula:
●​ where:
○​ k = key (the value you want to store)
○​ m = size of the hash table
○​ h(k) = index in the hash table
●​ The remainder ensures that the index always lies between 0 and m-1.

⚙️ Algorithm:-​
1.​ Choose a hash table size m (preferably a prime number to reduce collisions). For
each key k:
○​ Compute index = k % m.
○​ Place the key at index in the hash table.
2.​ If multiple keys map to the same index (collision), handle it using techniques like
chaining or linear probing.

💻 C Implementation (Simple Hash Table using Modulo Division):-



#include <stdio.h>

#define SIZE 10 // size of hash table

// Function to insert a key into hash table

void insert(int hashTable[], int key) {

int index = key % SIZE; // modulo division method

hashTable[index] = key; // store key at computed index

// Function to display hash table

void display(int hashTable[]) {

printf("Hash Table:\n");

for (int i = 0; i < SIZE; i++) {

if (hashTable[i] != -1)

printf("Index %d --> %d\n", i, hashTable[i]);

else

printf("Index %d --> Empty\n", i);

}
}

int main() {

int hashTable[SIZE];

// Initialize hash table with -1 (empty)

for (int i = 0; i < SIZE; i++)

hashTable[i] = -1;

// Keys to insert

int keys[] = {23, 43, 13, 27};

int n = sizeof(keys) / sizeof(keys[0]);

printf("Inserting keys using modulo division method...\n");

for (int i = 0; i < n; i++) {

insert(hashTable, keys[i]);

// Display hash table

display(hashTable);

return 0;

Fold Shift and Fold Boundary:-


The folding method divides a large key into smaller segments (usually equal-sized). These
segments are then combined (added or manipulated) to produce the hash value.

●​ Formula (general):

where a,b,c are segments of the key, and m is the table size.

Fold shift:- (also called folding–shifting) is a hashing method where:

1.​ The key (usually a long number) is split into equal-sized parts.​

2.​ All parts are added together.​

3.​ The resulting sum is then reduced using the hash table size:​
h(key)=(part1+part2+⋯+partn)mod tableSizeh(key) = (part_1 + part_2 + \dots +
part_n) \mod tableSizeh(key)=(part1​+part2​+⋯+partn​)modtableSize

Example:-
Key = 1234567, table size = 100

Split into 3-digit groups:


●​ 1 | 234 | 567​

Add:​
1 + 234 + 567 = 802

Hash:​
802 mod 100 = 2

Fold Boundary:-
Fold boundary (also called folding–boundary reversal) is similar, but:

●​ Every alternate part is reversed before adding.​

Example
Key = 1234567, split length = 3:

Parts: 1 | 234 | 567​


Reverse every second part:

●​ 1​

●​ 432 (reverse of 234)​

●​ 567​

Sum:​
1 + 432 + 567 = 1000

Hash:​
1000 mod 100 = 0

Algorithm:-

Fold Shift:-

Input: key, tableSize


1. Convert key to string
2. Split into equal parts of length L
3. Convert each part to integer
4. sum = sum of all parts
5. Return sum % tableSize

Fold Boundary:-

Input: key, tableSize


1. Convert key to string
2. Split into equal parts of length L
3. For every second part (i.e., part 2, 4, 6...), reverse digits
4. Convert each part to integer
5. sum = sum of all parts
6. Return sum % tableSize

C implementation for both methods:-

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

int foldShiftHash(char key[], int partSize, int tableSize) {


int len = strlen(key);
int sum = 0;

for (int i = 0; i < len; i += partSize) {


char part[20] = {0};
strncpy(part, key + i, partSize);
sum += atoi(part);
}
return sum % tableSize;
}

int foldBoundaryHash(char key[], int partSize, int tableSize) {


int len = strlen(key);
int sum = 0;
int partIndex = 0;

for (int i = 0; i < len; i += partSize) {


char part[20] = {0};
strncpy(part, key + i, partSize);

// Reverse every second part


if (partIndex % 2 == 1) {
int l = 0, r = strlen(part) - 1;
while (l < r) {
char temp = part[l];
part[l] = part[r];
part[r] = temp;
l++;
r--;
}
}
sum += atoi(part);
partIndex++;
}
return sum % tableSize;
}

int main() {
char key[50];
int partSize, tableSize;
printf("Enter numeric key: ");
scanf("%s", key);

printf("Enter part size (e.g., 2 or 3): ");


scanf("%d", &partSize);

printf("Enter hash table size: ");


scanf("%d", &tableSize);

int hashShift = foldShiftHash(key, partSize, tableSize);


int hashBoundary = foldBoundaryHash(key, partSize, tableSize);

printf("\nFold Shift Hash Value: %d\n", hashShift);


printf("Fold Boundary Hash Value: %d\n", hashBoundary);

return 0;
}

OUTPUT:-

Input:

Enter numeric key: 1234567


Enter part size: 3
Enter hash table size: 100

Output:-

Fold Shift Hash Value: 2


Fold Boundary Hash Value: 0

Direct and Subtraction Hashing:-

Direct Hashing:-

Definition
Direct hashing uses the key exactly as it is (or a simple function of it) as the hash address.

h(key)=keyh(key) = keyh(key)=key

or

h(key)=a×key+bh(key) = a \times key + bh(key)=a×key+b


When Used

●​ When the key range is small (e.g., 0–999)​

●​ When memory is not a limitation​

●​ Guarantees no collisions​

Example
Key = 45​
Table size = 100

h(45)=45h(45) = 45h(45)=45

Subtraction Hashing:

Definition

Subtraction hashing subtracts the key from a fixed number, then takes modulus of the
table size:

h(key)=(N−key)mod tableSizeh(key) = (N - key) \mod


tableSizeh(key)=(N−key)modtableSize

Where N is a fixed constant (usually power of 2 or the max key value).

✔ Example

Key = 45, table size = 100, N = 1000

h(45)=(1000−45)%100=955%100=55h(45) = (1000 - 45) \% 100 = 955 \% 100 =


55h(45)=(1000−45)%100=955%100=55

Algorithm:-

Direct Hashing:-

Input: key, tableSize


1. If key < tableSize
2. return key
3. Else return key % tableSize

Subtraction Hashing:-

Input: key, tableSize, N


1. Compute value = N - key
2. Hash = value % tableSize
3. Return hash
C Program Implementing Both Methods:-

#include <stdio.h>

int directHash(int key, int tableSize) {


// If key is out of range, use key % table size
if (key < tableSize)
return key;
else
return key % tableSize;
}

int subtractionHash(int key, int tableSize, int N) {


int value = N - key;
return value % tableSize;
}

int main() {
int key, tableSize, N;

printf("Enter the key: ");


scanf("%d", &key);

printf("Enter hash table size: ");


scanf("%d", &tableSize);

printf("Enter constant N (larger than key): ");


scanf("%d", &N);

int h1 = directHash(key, tableSize);


int h2 = subtractionHash(key, tableSize, N);

printf("\nDirect Hash Value: %d\n", h1);


printf("Subtraction Hash Value: %d\n", h2);

return 0;
}

OUTPUT:-

Input:-

Enter the key: 45


Enter hash table size: 100
Enter constant N: 1000

Output:-

Direct Hash Value: 45


Subtraction Hash Value: 55
Linear Probe for Collision Resolution:-

When using hashing, collisions occur if two keys hash to the same index.​
Linear Probing is a simple collision resolution technique where:

●​ If the desired slot is occupied, you check the next slot sequentially (index + 1, index
+ 2, …).
●​ Wrapping around happens when the end of the table is reached (modulo operation).
●​ This continues until an empty slot is found.

👉 Example:​
Hash function: h(key) = key % table_size​
If h(23) = 3 but slot 3 is full, try slot 4, then 5, etc.

📑 Algorithm (Linear Probing):-


Algorithm InsertLinearProbe(hashTable, key):

1. Compute index = key % table_size

2. If hashTable[index] is empty:

Place key at hashTable[index]

Else:

i=1

While hashTable[(index + i) % table_size] is not empty:

i=i+1

Place key at hashTable[(index + i) % table_size]

Algorithm SearchLinearProbe(hashTable, key):

1. Compute index = key % table_size

2. If hashTable[index] == key:

Return index

Else:

i=1

While hashTable[(index + i) % table_size] != key:

If slot is empty → Key not found


Else i = i + 1

Return (index + i) % table_size

💻 C Implementation:-
#include <stdio.h>

#define TABLE_SIZE 10

int hashTable[TABLE_SIZE];

// Initialize table with -1 (empty)

void initTable() {

for (int i = 0; i < TABLE_SIZE; i++)

hashTable[i] = -1;

// Hash function

int hashFunc(int key) {

return key % TABLE_SIZE;

// Insert using Linear Probing

void insert(int key) {

int index = hashFunc(key);

if (hashTable[index] == -1) {

hashTable[index] = key;

} else {

int i = 1;

while (hashTable[(index + i) % TABLE_SIZE] != -1) {

i++;

hashTable[(index + i) % TABLE_SIZE] = key;

}
}

// Search using Linear Probing

int search(int key) {

int index = hashFunc(key);

if (hashTable[index] == key) return index;

int i = 1;

while (hashTable[(index + i) % TABLE_SIZE] != -1) {

if (hashTable[(index + i) % TABLE_SIZE] == key)

return (index + i) % TABLE_SIZE;

i++;

return -1; // Not found

// Display table

void display() {

printf("\nHash Table:\n");

for (int i = 0; i < TABLE_SIZE; i++) {

printf("%d --> %d\n", i, hashTable[i]);

int main() {

initTable();

insert(23);

insert(43);

insert(13);

insert(27);

display();

int key = 43;

int pos = search(key);


if (pos != -1)

printf("\nKey %d found at index %d\n", key, pos);

else

printf("\nKey %d not found\n", key);

return 0;

🖥️ Sample Output (Dry Run):-


Hash Table:

0 --> -1

1 --> -1

2 --> -1

3 --> 23

4 --> 43

5 --> 13

6 --> -1

7 --> 27

8 --> -1

9 --> -1

Key 43 found at index 4

🔍 Explanation of Dry Run


●​ 23 % 10 = 3 → goes to index 3
●​ 43 % 10 = 3 → collision at 3 → next free slot is 4
●​ 13 % 10 = 3 → collision at 3 → next free slot is 5
●​ 27 % 10 = 7 → goes to index 7
EXPERIMENT NO. :-3

Implementing Stacks

Array Implementation:-

An array is a data structure that stores elements of the same type in contiguous
memory locations.

●​ Each element can be accessed directly using its index.


●​ Arrays are widely used to implement other data structures (like stacks, queues, hash
tables).
●​ Operations include insertion, deletion, traversal, searching.

👉 Example:​
If we declare int arr[5] = {10, 20, 30, 40, 50};

●​ arr[0] = 10, arr[1] = 20, etc.


●​ Memory is allocated sequentially.

📑 Algorithm (Basic Array Operations):-


Traversal:-

Algorithm TraverseArray(arr, n):


1. For i = 0 to n-1:
Print arr[i]

Insertion:-

Algorithm InsertArray(arr, n, pos, value):


1. For i = n down to pos+1:
arr[i] = arr[i-1] // shift right
2. arr[pos] = value
3. n = n + 1

Deletion:-

Algorithm DeleteArray(arr, n, pos):


1. For i = pos to n-2:
arr[i] = arr[i+1] // shift left
2. n = n - 1

💻 C Implementation:-
#include <stdio.h>
#define SIZE 10

// Traversal

void traverse(int arr[], int n) {

printf("Array elements: ");

for (int i = 0; i < n; i++)

printf("%d ", arr[i]);

printf("\n");

// Insertion

int insert(int arr[], int n, int pos, int value) {

if (n >= SIZE) {

printf("Array is full!\n");

return n;

for (int i = n; i > pos; i--) {

arr[i] = arr[i-1];

arr[pos] = value;

return n + 1;

// Deletion

int delete(int arr[], int n, int pos) {

if (n <= 0) {

printf("Array is empty!\n");

return n;

for (int i = pos; i < n-1; i++) {

arr[i] = arr[i+1];

return n - 1;
}

int main() {

int arr[SIZE] = {10, 20, 30, 40, 50};

int n = 5;

printf("Initial ");

traverse(arr, n);

// Insert 25 at position 2

n = insert(arr, n, 2, 25);

printf("After Insertion (25 at pos 2): ");

traverse(arr, n);

// Delete element at position 4

n = delete(arr, n, 4);

printf("After Deletion (pos 4): ");

traverse(arr, n);

return 0;

🖥️ Sample Output (Dry Run):-


Initial Array elements: 10 20 30 40 50

After Insertion (25 at pos 2): 10 20 25 30 40 50

After Deletion (pos 4): 10 20 25 30 50

🔍 Explanation of Dry Run


●​ Start: [10, 20, 30, 40, 50]
●​ Insert 25 at position 2: shift right → [10, 20, 25, 30, 40, 50]
●​ Delete element at position 4 (value 40): shift left → [10, 20, 25, 30, 50]
Linked List implementation:-

A linked list is a dynamic data structure where elements (called nodes) are connected using
pointers.​
Each node contains:

●​ Data (the value you want to store)


●​ Pointer (address of the next node)

Unlike arrays:

●​ Memory is not contiguous.


●​ Size can grow/shrink dynamically.
●​ Insertion/deletion is easier (no shifting needed).

👉We’llTypes: Singly Linked List, Doubly Linked List, Circular Linked List.​
start with Singly Linked List.

📑 Algorithm (Singly Linked List Basic Operations):-


Create Node:

Algorithm CreateNode(value):

1. Allocate memory for new node

2. Set node->data = value

3. Set node->next = NULL

4. Return node

Insert at End:

Algorithm InsertEnd(head, value):

1. Create new node with value

2. If head == NULL:

head = new node

Else:

Traverse till last node

last->next = new node


Delete Node:

Algorithm DeleteNode(head, value):

1. If head == NULL → return

2. If head->data == value:

head = head->next

free old head

3. Else:

Traverse until node->next->data == value

temp = node->next

node->next = temp->next

free temp

Traverse(Display):

Algorithm Traverse(head):

1. Set temp = head

2. While temp != NULL:

Print temp->data

temp = temp->next

💻 C Implementation:-
#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 value) {

struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

newNode->data = value;

newNode->next = NULL;

return newNode;

// Insert at end

void insertEnd(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;

// Delete a node by value

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

if (*head == NULL) return;


struct Node* temp = *head;

// If head node itself holds the value

if (temp->data == value) {

*head = temp->next;

free(temp);

return;

// Search for the node to delete

struct Node* prev = NULL;

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

prev = temp;

temp = temp->next;

if (temp == NULL) return; // Value not found

prev->next = temp->next;

free(temp);

// Display linked list

void display(struct Node* head) {

struct Node* temp = head;

printf("Linked List: ");

while (temp != NULL) {

printf("%d -> ", temp->data);

temp = temp->next;

}
printf("NULL\n");

int main() {

struct Node* head = NULL;

insertEnd(&head, 10);

insertEnd(&head, 20);

insertEnd(&head, 30);

insertEnd(&head, 40);

display(head);

deleteNode(&head, 20);

printf("After deleting 20:\n");

display(head);

return 0;

🖥️ Sample Output (Dry Run):-


Linked List: 10 -> 20 -> 30 -> 40 -> NULL

After deleting 20:

Linked List: 10 -> 30 -> 40 -> NULL

🔍 Explanation of Dry Run:


●​ Inserted nodes: 10 → 20 → 30 → 40 → NULL
●​ Deleted node with value 20: list becomes 10 → 30 → 40 → NULL

Evaluation of postfix expression and balancing of


parenthesis:-

Evaluation of Postfix Expression:-

●​ Postfix (Reverse Polish Notation): Operators come after operands.​


Example: 23*54*+9- means (2*3) + (5*4) - 9.
●​ Why stack?
●​ Operands are pushed onto the stack.
●​ When an operator is encountered, pop required operands, apply
operation, push result back.
●​ Continue until expression ends.

📑 Algorithm (Postfix Evaluation):-


Algorithm EvaluatePostfix(expr):

1. Initialize empty stack

2. For each symbol in expr:

a. If symbol is operand → push onto stack

b. If symbol is operator:

i. Pop two operands (op2, op1)

ii. result = op1 operator op2

iii. Push result back

3. Final result = pop from stack

C Implementation (Postfix Evaluation):-

#include <stdio.h>

#include <ctype.h> // for isdigit

#include <stdlib.h> // for atoi


#define MAX 100

int stack[MAX];

int top = -1;

void push(int x) {

stack[++top] = x;

int pop() {

return stack[top--];

int evaluatePostfix(char* expr) {

for (int i = 0; expr[i] != '\0'; i++) {

char ch = expr[i];

if (isdigit(ch)) {

push(ch - '0'); // convert char to int

} else {

int val2 = pop();

int val1 = pop();

switch (ch) {

case '+': push(val1 + val2); break;

case '-': push(val1 - val2); break;

case '*': push(val1 * val2); break;

case '/': push(val1 / val2); break;


}

return pop();

int main() {

char expr[] = "23*54*+9-"; // (2*3)+(5*4)-9

printf("Postfix Expression: %s\n", expr);

printf("Evaluated Result: %d\n", evaluatePostfix(expr));

return 0;

🖥️ Sample Output (Postfix Evaluation):


Postfix Expression: 23*54*+9-

Evaluated Result: 17

Balancing of Parentheses:-
●​ Problem: Check if every opening bracket has a matching closing bracket
in correct order.
●​ Why stack?
●​ Push opening brackets (, {, [ onto stack.
●​ On encountering closing bracket, check top of stack.
●​ If mismatch → unbalanced.
●​ If stack empty at end → balanced.

📑 Algorithm (Balancing Parentheses):-


Algorithm CheckBalanced(expr):

1. Initialize empty stack


2. For each char in expr:

a. If opening bracket → push

b. If closing bracket:

i. If stack empty → Not balanced

ii. Pop top and check if matches

3. If stack empty at end → Balanced

Else → Not balanced

💻 C Implementation (Balancing Parentheses):-


#include <stdio.h>

#include <stdbool.h>

#define MAX 100

char stack2[MAX];

int top2 = -1;

void push2(char c) {

stack2[++top2] = c;

char pop2() {

return stack2[top2--];

bool isMatchingPair(char open, char close) {

return (open == '(' && close == ')') ||


(open == '{' && close == '}') ||

(open == '[' && close == ']');

bool checkBalanced(char* expr) {

for (int i = 0; expr[i] != '\0'; i++) {

char ch = expr[i];

if (ch == '(' || ch == '{' || ch == '[') {

push2(ch);

} else if (ch == ')' || ch == '}' || ch == ']') {

if (top2 == -1) return false;

char open = pop2();

if (!isMatchingPair(open, ch)) return false;

return (top2 == -1);

int main() {

char expr1[] = "{[()]}";

char expr2[] = "{[(])}";

printf("Expression: %s --> %s\n", expr1, checkBalanced(expr1) ?


"Balanced" : "Not Balanced");

printf("Expression: %s --> %s\n", expr2, checkBalanced(expr2) ?


"Balanced" : "Not Balanced");

return 0;

}
🖥️ Sample Output (Balancing Parentheses):
Expression: {[()]} -->

Balanced Expression: {[(])} --> Not Balanced

Wrap-Up:

●​ Postfix Evaluation: Uses stack to compute expressions without


parentheses.
●​ Balancing Parentheses: Uses stack to validate correct nesting of
brackets.

Both are classic stack applications and essential for compiler design,
parsing, and expression evaluation.

Conversion of infix to postfix notation:-

●​ Infix: Operators are written between operands. Example: A + B * C Postfix


(Reverse Polish Notation): Operators are written after operands. Example: A B C *
+
●​ Why stack?
●​ Operands are directly added to the output.
●​ Operators are pushed onto a stack, respecting precedence and associativity.
●​ Parentheses control grouping.

📑 Algorithm (Shunting Yard Method):-


Algorithm CheckBalanced(expr):

1. Initialize empty stack

2. For each char in expr:

a. If opening bracket → push

b. If closing bracket:

i. If stack empty → Not balanced

ii. Pop top and check if matches

3. If stack empty at end → Balanced

Else → Not balanced


💻 C Implementation:-
#include <stdio.h>

#include <stdbool.h>

#define MAX 100

char stack2[MAX];

int top2 = -1;

void push2(char c) {

stack2[++top2] = c;

char pop2() {

return stack2[top2--];

bool isMatchingPair(char open, char close) {

return (open == '(' && close == ')') ||

(open == '{' && close == '}') ||

(open == '[' && close == ']');

bool checkBalanced(char* expr) {

for (int i = 0; expr[i] != '\0'; i++) {

char ch = expr[i];

if (ch == '(' || ch == '{' || ch == '[') {

push2(ch);

} else if (ch == ')' || ch == '}' || ch == ']') {

if (top2 == -1) return false;

char open = pop2();

if (!isMatchingPair(open, ch)) return false;

return (top2 == -1);


}

int main() {

char expr1[] = "{[()]}";

char expr2[] = "{[(])}";

printf("Expression: %s --> %s\n", expr1, checkBalanced(expr1) ? "Balanced" : "Not


Balanced");

printf("Expression: %s --> %s\n", expr2, checkBalanced(expr2) ? "Balanced" : "Not


Balanced");

return 0;

🖥️ Sample Output (Dry Run):


Infix Expression: A+B*C

Postfix Expression: ABC*+

🔍 Explanation of Dry Run:


●​ Input: A + B * C
●​ Precedence: * > +
●​ Steps:
○​ Read A → output A
○​ Read + → push +
○​ Read B → output B
○​ Read * → higher precedence than + → push *
○​ Read C → output C
○​ End → pop * then +
●​ Result: A B C * +






You might also like