Data Structure
Data Structure
MADE BY:
MD. ASHIKUZZ ZAMAN (ASHIK)
ID: 220119
INDEX
1. Data Structure Definition and Operations 3
2. Recursion: 4
3. Sorting: 5
4. Array: 2D 8
4. Stack: 9
5. Queue: 10
6. Circular Queue: 11
7. Linkedlist: 13
8. Polish Notation: 16
9. Tree: 17
11. Spanning Tree: 2
12. Heap: 24
13. Hash Table: 26
1. Data Structure Definition and Operations
A data structure is a way of organizing and managing data so that it can be used
efficiently.
Basic Operations
Traversing: Visiting each element in a data structure to access or display its contents.
Searching: Finding a specific element within a data structure.
Insertion: Adding a new element into a data structure.
Deletion: Removing an existing element from a data structure.
Sorting: Arranging elements in a specific order (e.g., ascending or descending).
Merging: Combining elements from two or more data structures into one.
Recursion is the process in which a function calls itself again and again.
● Base Case: The condition under which the recursion stops, preventing infinite recursion
and eventual stack overflow.
● Recursive Case: The part of the function where it calls itself with modified arguments to
work towards the base case.
Factorial:
int factorial(int n) {
if (n <= 1) {
return 1; // Base case
} else {
return n * factorial(n - 1); // Recursive case
}
}
Fibonacci:
int fibonacci(int n) {
if (n <= 1) {
return n; // Base case
} else {
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive case
}
}
Iterative Implementation:
int fibonacci(int n) {
if (n <= 1) {
return n;
}
int a = 0, b = 1, c;
for (int i = 2; i <= n; ++i) {
c = a + b;
a = b;
b = c;
}
return b;
}
3. Sorting:
A Sorting Algorithm is used to rearrange a given array or list of elements according to a
comparison operator on the elements.
Bubble Sort: Repeatedly swaps adjacent elements if they are in the wrong order.
Selection Sort: Selects the smallest (or largest) element from the unsorted portion and places it
in the correct position.
Insertion Sort: Builds the sorted array one element at a time by inserting each new element
into its proper position.
Merge Sort: Divides the array into halves, recursively sorts each half, and then merges the
sorted halves.
Quick Sort: Chooses a pivot element, partitions the array around the pivot, and recursively
sorts the partitions.
1. Bubble Sort:
Steps:
1. Pass 1:
○ [1, 5, 4, 2, 8] (5 and 1 swapped)
○ [1, 4, 5, 2, 8] (5 and 4 swapped)
○ [1, 4, 2, 5, 8] (5 and 2 swapped)
○ [1, 4, 2, 5, 8] (8 is in the correct position)
2. Pass 2:
○ [1, 4, 2, 5, 8] (no swap needed between 1 and 4)
○ [1, 2, 4, 5, 8] (4 and 2 swapped)
3. Pass 3:
○ [1, 2, 4, 5, 8] (no swap needed)
4. Pass 4:
○ [1, 2, 4, 5, 8] (no swap needed)
C++ code:
void bubbleSort(int arr[], int n) {
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]);//make a swap function
}
}
}
}
2. Selection Sort:
Steps:
1. Pass 1:
○ Find minimum in [5, 1, 4, 2, 8]: Minimum is 1
○ Swap 5 with 1: [1, 5, 4, 2, 8]
2. Pass 2:
○ Find minimum in [5, 4, 2, 8]: Minimum is 2
○ Swap 5 with 2: [1, 2, 4, 5, 8]
3. Pass 3:
○ Find minimum in [4, 5, 8]: Minimum is 4
○ No swap needed: [1, 2, 4, 5, 8]
4. Pass 4:
○ Find minimum in [5, 8]: Minimum is 5
○ No swap needed: [1, 2, 4, 5, 8]
Pseudocode:
procedure selectionSort(array, size)
for i from 0 to size - 1 do
set minIndex to i
for j from i + 1 to size - 1 do
if array[j] < array[minIndex]
set minIndex to j
if minIndex is not i
swap array[i] with array[minIndex]
end selectionSort
C++ code:
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; ++i) {
int minIdx = i;
for (int j = i + 1; j < n; ++j) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
if (minIdx != i) {
// Swap without using std::swap
int temp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = temp;
}
}
}
3. Insertion Sort:
Pseudocode:
procedure insertionSort(array, size)
for i from 1 to size - 1 do
set key to array[i]
set j to i - 1
while j >= 0 and array[j] > key do
array[j + 1] to array[j]
set j to j - 1
end while
array[j + 1] to key
end insertionSort
C++ code:
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
If you are interested. You can read marge and selection sort..!
4. Array: 2D
Sum of Prime Numbers:
bool isPrime(int num) {
if (num <= 1) return false;
for (int i = 2; i <= sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
// Function to calculate the sum of prime numbers in a 2D array
int sumOfPrimes(int arr[][10], int n) {
int sum = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (isPrime(arr[i][j])) {
sum += arr[i][j];
}
}
}
return sum;
}
}
Sum of Boundary Element:
int boundary(int matrix[100][100], int n) {
int boundary_sum = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {
boundary_sum += matrix[i][j];
}
}
return boundary_sum;
}
4. Stack:
A stack is a data structure that follows the Last In First Out (LIFO) principle. Elements can
only be added or removed from the top of the stack.
Operations:
Applications:
public:
void push(Type value){
arr[++last]=value;
}
void pop(){
--last;
}
Type top(){
return arr[last];
}
int size(){
return last+1;
}
bool empty(){
if(last==-1) return true;
return false;
}
5. Queue:
A queue is a data structure that follows the First In First Out (FIFO) principle. Elements
are added at the back (rear) and removed from the front (front) of the queue.
Operations:
Applications:
● Task Scheduling: Useful in operating systems for managing tasks in the correct
order.
● Breadth-First Search (BFS): Used in graph traversal algorithms.
● Printers and Job Queues: Jobs are processed in the order they are received.
public:
// Enqueue: Adds element to the rear of the queue
void enqueue(Type value) {
arr[++rear] = value;
size++;
}
Definition:
A Circular Queue is a linear data structure that follows the FIFO (First In, First Out) principle
but uses a circular arrangement of elements. It connects the end of the queue back to the
beginning to make a circular structure, thereby utilizing the entire array space efficiently.
Operations:
1. Enqueue: Add an element to the rear of the queue. If the rear reaches the end of
2. Dequeue: Remove an element from the front of the queue. The front pointer moves
3. Peek: View the front element of the queue without removing it.
4. isEmpty: Check if the queue is empty. This is typically done by checking if the front
5. isFull: Check if the queue is full. This can be determined by checking if the next
position of the rear pointer (in circular fashion) is the front pointer.
Linear Queue:
Circular Queue:
○ In a traditional queue, when the rear reaches the end of the array, the space
at the front may remain unused even though it could potentially be utilized. A
○ Circular queues make better use of the available space by wrapping around
to the beginning of the array. This reduces wasted memory and optimizes
resource use.
3. Simplified Implementation:
4. Fixed Size:
○ Like traditional queues, circular queues also have a fixed size. However, their
7. Linkedlist:
A Linked List is an Abstract Data Type (ADT) that holds a collection of nodes. Each node
contains data and a reference (or pointer) to the next node in the sequence. Linked lists are
used to implement dynamic data structures that can grow or shrink in size.
struct Node {
int data;
Node* next;
Node(int val){
data=val;
next=nullptr;
}
};
void insertHead(int value) {
Node* newNode = new Node(value);
newNode->next = head;
head = newNode;
}
void pop() {
if (Head == nullptr) {
cout << "Queue is Emptly !\n";
return;
}
else if (Head->next == nullptr) {
delete Head;
Head = nullptr;
return;
}
else {
Node *temp = Head;
while (temp->next->next != nullptr) {
temp = temp->next;
}
delete temp->next;
temp->next = nullptr;
}
}
1. Dynamic Size:
○ Flexible Growth: Linked lists can grow or shrink in size as needed, without
requiring an initial size. Memory is allocated only when needed.
2. No Memory Wastage:
○ Efficient Use: Memory is used only for the nodes that are needed. There’s no
pre-allocation of memory or wasted space, as with arrays.
3. Easy Implementation:
○ Simple Structures: Data structures like stacks and queues are easier to
implement using linked lists due to their flexible nature.
4. Efficient Insertion and Deletion:
○ Quick Updates: Adding or removing elements is straightforward and quick.
You only need to update pointers, without shifting other elements as you do
in arrays.
5. Flexible Memory Usage:
○ Non-Contiguous: Linked lists do not require elements to be stored in
contiguous memory locations, which can be advantageous for memory
management.
6. Handles Large Data Well:
○ Dynamic Adjustment: Ideal for working with large datasets as they can
dynamically adjust their size and handle large amounts of data efficiently.
7. Scalable:
○ Adaptable Size: Easily allows adding or removing elements at any position in
the list without major adjustments.
8. Polish Notation:
Algorithm:
Evaluate Expression: 5 2 * 3 6 2 ^ / + 5 5 - * -2 -
9. Tree:
A tree is a kind of data structure that is used to represent the data in hierarchical form.
● A Binary Search Tree is a Binary Tree where every node's left child has a lower value,
and every node's right child has a higher value.
#include<iostream>
using namespace std;
struct Node{
int data;
Node *left,*right;
Node(int val) {
data=val;
left=right=nullptr;
}
};
if (cur != root)
{
if (cur == parent->left)
parent->left = child;
else
parent->right = child;
}
else
root = child;
Construct graph:
BFS:
11. Spanning Tree:
A spanning tree is a subset of Graph G, such that all the vertices are connected using the
minimum possible number of edges.
Properties:
Normal Graph:
Spanning Tree:
Minimum Spanning Tree (MST):
The minimum spanning tree is a spanning tree whose sum of the edges is minimum. Consider
the below graph that contains the edge weight.
Kruskal’s algorithm:
Below are the steps for finding MST using Kruskal’s algorithm:
1. Sort all the edges in non-decreasing order of their weight.
2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far. If
the cycle is not formed, include this edge. Else, discard it.
3. Repeat step#2 until there are (V-1) edges in the spanning tree.
Prim's Algorithm:
Minimum Spanning Tree (MST) is to build the MST incrementally by starting with a single
vertex and gradually extending the tree by adding the closest neighboring vertex at each step.
Below are the steps for finding MST using Prim’s algorithm:
1. Start by picking any vertex and add it to the MST.
2. Look for the smallest edge that connects a vertex already in the MST to a vertex not yet
in the MST.
3. Add that edge and vertex to the MST.
4. Repeat this process until all vertices are included in the MST.
12. Heap:
A Heap is a complete binary tree data structure that satisfies the heap property: for every node,
the value of its children is greater than or equal to its own value. Heaps are usually used to
implement priority queues, where the smallest (or largest) element is always at the root of the
tree.
Types of Heaps
There are two main types of heaps:
● Max Heap: The root node contains the maximum value, and the values decrease as you
move down the tree.
● Min Heap: The root node contains the minimum value, and the values increase as you
move down the tree.
Max Heapify:
Min Heapify:
13. Hash Table:
A hash table is a way to store and retrieve key-value pairs efficiently. It works as follows:
● Key: The input (like a string or number) used to find where to store or retrieve data.
● Hash Function: Takes the key and calculates an index in the hash table.
● Hash Table: An array where data is stored at the index given by the hash function.
Collisions: When two keys hash to the same index, a collision occurs. Common methods to
handle collisions include:
● Chaining: Each index holds a list of all entries that hash to that index.
● Open Addressing: If a slot is taken, it finds another slot using:
○ Linear Probing: Check the next slot until you find an empty one.
○ Quadratic Probing: Use a pattern to skip over slots.
○ Double Hashing: Use a second hash function to find the next slot.
Hashing:
● Hashing is a technique used in data structures that efficiently stores and retrieves data
in a way that allows for quick access.
Hash collision:
● A hash collision occurs when two different keys produce the same hash address or
index in the hash table. This can happen when a hash function maps multiple keys to the
same location. To handle collisions, several methods can be used. One common method
is linear probing, which means that when a collision occurs, you check the next available
memory slot (i.e., increase the index by 1 until an empty spot is found).
Given: The table has 11 memory locations. Using linear probing, the records will be placed as
follows:
Records and Their Hashing:
● Slot 0: F
● Slot 1: H
● Slot 2: C
● Slot 4: A
● Slot 5: E
● Slot 6: G
● Slot 8: B
The End