Algorithms and Data Structures Notes (C#
Examples Included)
1. Fundamental Principles of Algorithms
1.1 Algorithm Principles
What is an Algorithm?
An algorithm is a step-by-step procedure used to solve a problem or perform a task.
Characteristics of a Good Algorithm
• Clear and easy to understand
• Produces correct results
• Efficient in time and memory usage
• Finite (must end after a number of steps)
Everyday Example of an Algorithm
Making tea: 1. Boil water 2. Put tea leaves or tea bag in a cup 3. Pour hot water 4. Add sugar or milk 5.
Stir and serve
1.2 Characteristics of an Algorithm
An algorithm should have the following characteristics:
1. Input
The algorithm should accept zero or more inputs.
2. Output
The algorithm should produce at least one output.
3. Definiteness
Every step must be clearly defined.
4. Finiteness
The algorithm must stop after a finite number of steps.
5. Effectiveness
Each step should be simple and executable.
1
Example Algorithm
Algorithm to add two numbers: 1. Start 2. Input first number 3. Input second number 4. Add the
numbers 5. Display result 6. Stop
1.3 Principles of Algorithm Writing
Rules for Writing Algorithms
• Use simple language
• Steps should be in order
• Avoid ambiguity
• Use meaningful variable names
• Keep the algorithm efficient
Example: Find the Largest Number
1. Start
2. Input first number
3. Input second number
4. Compare the numbers
5. Display the larger number
6. Stop
C# Example
using System;
class LargestNumber
{
static void Main()
{
int a = 10;
int b = 20;
if (a > b)
{
[Link]("Largest number is: " + a);
}
else
{
[Link]("Largest number is: " + b);
}
}
}
2
1.4 Algorithm Analysis
Algorithm analysis is the process of measuring:
• Execution time
• Memory usage
Why Analyze Algorithms?
• To compare solutions
• To improve efficiency
• To reduce resource usage
Types of Analysis
1. Time Complexity
Measures how fast an algorithm runs.
2. Space Complexity
Measures memory used by the algorithm.
Example
A loop that runs 10 times is faster than one that runs 1,000,000 times.
1.5 Complexities of Algorithms
1.5.1 Space Complexity
Space complexity refers to the amount of memory an algorithm uses.
Example
using System;
class SpaceExample
{
static void Main()
{
int number = 10;
[Link](number);
}
}
This program uses very little memory because it stores only one variable.
3
1.5.2 Time Complexity
Time complexity measures the running time of an algorithm.
Common Time Complexities
Complexity Meaning
O(1) Constant time
O(n) Linear time
O(n²) Quadratic time
O(log n) Logarithmic time
Example of O(n)
using System;
class TimeComplexity
{
static void Main()
{
int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < [Link]; i++)
{
[Link](numbers[i]);
}
}
}
The loop runs once for each element in the array.
1.6 Greedy Algorithms
A greedy algorithm solves a problem step-by-step by choosing the best option at each stage.
Characteristics
• Makes local optimal choices
• Simple and fast
• Does not always give the best global solution
1.6.1 Counting Coins
This problem finds the minimum number of coins needed for a given amount.
4
Example
Coins available:
• 10
•5
•1
Amount = 28
Solution:
• 2 × 10 = 20
•1×5=5
•3×1=3
Total coins = 6
C# Program
using System;
class CoinCounting
{
static void Main()
{
int amount = 28;
int[] coins = {10, 5, 1};
foreach (int coin in coins)
{
int count = amount / coin;
if (count > 0)
{
[Link](coin + " used " + count + " times");
amount = amount % coin;
}
}
}
}
1.7 Divide and Conquer Algorithms
Divide and conquer algorithms solve problems by: 1. Dividing the problem into smaller parts 2. Solving
each part 3. Combining the solutions
5
Examples:
• Merge Sort
• Binary Search
1.7.1 Divide/Break
The problem is divided into smaller sub-problems.
Example
Searching a number in a sorted array by splitting the array into halves.
1.7.2 Conquer/Solve
Each smaller problem is solved independently.
Binary Search Example in C
using System;
class BinarySearch
{
static void Main()
{
int[] numbers = {1, 3, 5, 7, 9};
int target = 7;
int left = 0;
int right = [Link] - 1;
while (left <= right)
{
int middle = (left + right) / 2;
if (numbers[middle] == target)
{
[Link]("Number found at index " + middle);
return;
}
else if (numbers[middle] < target)
{
left = middle + 1;
}
else
{
right = middle - 1;
6
}
}
[Link]("Number not found");
}
}
1.7.3 Merge/Combine
After solving smaller problems, the solutions are combined.
Example
Merge Sort combines sorted sub-arrays into one sorted array.
2. Fundamental Concepts of Data Structures
2.1 Key Concepts in Data Structures
Data structures are ways of organizing and storing data.
Importance of Data Structures
• Efficient data storage
• Faster searching and sorting
• Better memory management
Examples:
• Arrays
• Linked Lists
• Stacks
• Queues
• Trees
2.1.1 Data
Data refers to raw facts and figures.
Examples:
• Numbers
• Names
• Marks
• Dates
7
C# Example
string name = "John";
int age = 20;
2.1.2 Object
An object is an instance of a class.
Object Characteristics
• State (properties)
• Behavior (methods)
C# Example
using System;
class Student
{
public string name;
public int age;
}
class Program
{
static void Main()
{
Student s1 = new Student();
[Link] = "Mary";
[Link] = 21;
[Link]([Link]);
[Link]([Link]);
}
}
2.1.3 Data Type
A data type defines the kind of data a variable can store.
8
Common Data Types in C
Data Type Description Example
int Integer numbers 10
double Decimal numbers 10.5
char Single character 'A'
string Text "Hello"
bool True or false true
Example
int marks = 80;
double price = 100.50;
char grade = 'A';
string school = "Tech School";
bool passed = true;
2.2 Explanation of Arrays
An array is a collection of elements of the same data type stored in contiguous memory locations.
Features of Arrays
• Fixed size
• Stores similar data types
• Uses indexes
Example
using System;
class ArrayExample
{
static void Main()
{
int[] numbers = {10, 20, 30, 40};
[Link](numbers[0]);
[Link](numbers[1]);
}
}
9
2.3 Array Insertion Operations
Insertion means adding an element into an array.
2.3.1 At the Beginning
Example
Insert 5 at the beginning.
Original: 10 20 30
New Array: 5 10 20 30
C# Example
using System;
class InsertBeginning
{
static void Main()
{
int[] oldArray = {10, 20, 30};
int[] newArray = new int[4];
newArray[0] = 5;
for (int i = 0; i < [Link]; i++)
{
newArray[i + 1] = oldArray[i];
}
foreach (int item in newArray)
{
[Link](item + " ");
}
}
}
2.3.2 At the Given Index
Example
Insert 15 at index 1.
10
Original: 10 20 30
Result: 10 15 20 30
C# Example
using System;
class InsertIndex
{
static void Main()
{
int[] oldArray = {10, 20, 30};
int[] newArray = new int[4];
int index = 1;
int value = 15;
for (int i = 0; i < index; i++)
{
newArray[i] = oldArray[i];
}
newArray[index] = value;
for (int i = index; i < [Link]; i++)
{
newArray[i + 1] = oldArray[i];
}
foreach (int item in newArray)
{
[Link](item + " ");
}
}
}
2.3.3 After the Given Index
Example
Insert 25 after index 1.
Original: 10 20 30
Result: 10 20 25 30
11
C# Example
using System;
class InsertAfterIndex
{
static void Main()
{
int[] oldArray = {10, 20, 30};
int[] newArray = new int[4];
int index = 1;
int value = 25;
for (int i = 0; i <= index; i++)
{
newArray[i] = oldArray[i];
}
newArray[index + 1] = value;
for (int i = index + 1; i < [Link]; i++)
{
newArray[i + 1] = oldArray[i];
}
foreach (int item in newArray)
{
[Link](item + " ");
}
}
}
2.3.4 Before the Given Index
Example
Insert 15 before index 1.
Original: 10 20 30
Result: 10 15 20 30
C# Example
using System;
12
class InsertBeforeIndex
{
static void Main()
{
int[] oldArray = {10, 20, 30};
int[] newArray = new int[4];
int index = 1;
int value = 15;
for (int i = 0; i < index; i++)
{
newArray[i] = oldArray[i];
}
newArray[index] = value;
for (int i = index; i < [Link]; i++)
{
newArray[i + 1] = oldArray[i];
}
foreach (int item in newArray)
{
[Link](item + " ");
}
}
}
2.4 Array Delete, Search and Update
1. Delete Operation
Deletion removes an element from an array.
Example
Remove 20 from: 10 20 30
Result: 10 30
C# Example
using System;
class DeleteArray
{
13
static void Main()
{
int[] numbers = {10, 20, 30};
for (int i = 0; i < [Link]; i++)
{
if (numbers[i] != 20)
{
[Link](numbers[i] + " ");
}
}
}
}
2. Search Operation
Searching finds the location of an element.
C# Example
using System;
class SearchArray
{
static void Main()
{
int[] numbers = {10, 20, 30, 40};
int target = 30;
for (int i = 0; i < [Link]; i++)
{
if (numbers[i] == target)
{
[Link]("Found at index: " + i);
}
}
}
}
3. Update Operation
Updating changes an existing value.
Example
Change 20 to 25.
14
C# Example
using System;
class UpdateArray
{
static void Main()
{
int[] numbers = {10, 20, 30};
numbers[1] = 25;
foreach (int item in numbers)
{
[Link](item + " ");
}
}
}
2.5 Demonstration of Array Operations
This program demonstrates insertion, searching, updating and deletion.
Complete C# Example
using System;
class ArrayOperations
{
static void Main()
{
int[] numbers = {10, 20, 30, 40};
[Link]("Original Array:");
foreach (int n in numbers)
{
[Link](n + " ");
}
[Link]();
// Update
numbers[1] = 25;
[Link]("Updated Array:");
foreach (int n in numbers)
{
15
[Link](n + " ");
}
[Link]();
// Search
int target = 30;
for (int i = 0; i < [Link]; i++)
{
if (numbers[i] == target)
{
[Link]("30 found at index " + i);
}
}
[Link]();
// Delete (display without 40)
[Link]("After deleting 40:");
foreach (int n in numbers)
{
if (n != 40)
{
[Link](n + " ");
}
}
}
}
3. Linked Lists
3.1 Linked Lists
A linked list is a linear data structure where elements are connected using pointers or references.
Each element is called a node.
A node contains:
• Data
• Reference to the next node
Advantages of Linked Lists
• Dynamic size
• Easy insertion and deletion
16
• Efficient memory usage
Disadvantages
• Extra memory needed for links
• Slower access compared to arrays
3.1.1 Linked List Representation
Structure of a Node
A node contains: 1. Data 2. Next pointer
Representation
[Data | Next]
Example
10 → 20 → 30 → NULL
C# Example
using System;
class Node
{
public int data;
public Node next;
public Node(int value)
{
data = value;
next = null;
}
}
class Program
{
static void Main()
{
Node first = new Node(10);
Node second = new Node(20);
Node third = new Node(30);
[Link] = second;
[Link] = third;
17
Node current = first;
while (current != null)
{
[Link]([Link] + " -> ");
current = [Link];
}
[Link]("NULL");
}
}
3.1.2 Types of Linked Lists
1. Singly Linked List
Each node points to the next node only.
10 → 20 → 30 → NULL
2. Doubly Linked List
Each node has:
• Previous pointer
• Next pointer
NULL ← 10 ⇄ 20 ⇄ 30 → NULL
3. Circular Linked List
The last node points back to the first node.
10 → 20 → 30
↑ ↓
└─────────┘
3.2 Doubly Linked Lists
A doubly linked list allows movement in both directions.
18
Each node contains:
• Previous reference
• Data
• Next reference
3.2.1 Representation
Structure
[Prev | Data | Next]
Example
NULL ← 10 ⇄ 20 ⇄ 30 → NULL
C# Example
using System;
class Node
{
public int data;
public Node prev;
public Node next;
public Node(int value)
{
data = value;
}
}
class Program
{
static void Main()
{
Node first = new Node(10);
Node second = new Node(20);
Node third = new Node(30);
[Link] = second;
[Link] = first;
[Link] = third;
[Link] = second;
19
Node current = first;
while (current != null)
{
[Link]([Link] + " ⇄ ");
current = [Link];
}
[Link]("NULL");
}
}
3.2.2 Basic Operations
1. Insertion
Adding a new node.
2. Deletion
Removing a node.
3. Traversal
Moving through nodes.
4. Searching
Finding a node.
3.3 Circular Linked Lists
In a circular linked list, the last node connects back to the first node.
Features
• No NULL at the end
• Useful in circular processes
• Efficient for repeated traversal
20
3.3.1 Representation
Example
10 → 20 → 30
↑ ↓
└─────────┘
C# Example
using System;
class Node
{
public int data;
public Node next;
public Node(int value)
{
data = value;
}
}
class Program
{
static void Main()
{
Node first = new Node(10);
Node second = new Node(20);
Node third = new Node(30);
[Link] = second;
[Link] = third;
[Link] = first;
Node current = first;
for (int i = 0; i < 6; i++)
{
[Link]([Link] + " -> ");
current = [Link];
}
}
}
21
3.3.2 Basic Operations
Operations in Circular Linked Lists
• Insertion
• Deletion
• Traversal
• Searching
3.4 Demonstration of Basic Operations for Various Linked Lists
Using C
3.4.1 Insertion
C# Example
using System;
class Node
{
public int data;
public Node next;
public Node(int value)
{
data = value;
}
}
class LinkedList
{
public Node head;
public void Insert(int value)
{
Node newNode = new Node(value);
if (head == null)
{
head = newNode;
}
else
{
Node current = head;
while ([Link] != null)
22
{
current = [Link];
}
[Link] = newNode;
}
}
public void Display()
{
Node current = head;
while (current != null)
{
[Link]([Link] + " -> ");
current = [Link];
}
[Link]("NULL");
}
}
class Program
{
static void Main()
{
LinkedList list = new LinkedList();
[Link](10);
[Link](20);
[Link](30);
[Link]();
}
}
3.4.2 Deletion
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
List<int> numbers = new List<int>() {10, 20, 30, 40};
23
[Link](20);
foreach (int item in numbers)
{
[Link](item + " ");
}
}
}
3.4.3 Reverse
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
List<int> numbers = new List<int>() {10, 20, 30};
[Link]();
foreach (int item in numbers)
{
[Link](item + " ");
}
}
}
3.4.4 Display
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
List<int> numbers = new List<int>() {10, 20, 30};
24
foreach (int item in numbers)
{
[Link](item);
}
}
}
4. Stacks and Queues
4.1 Definition of Stacks
A stack is a linear data structure that follows:
LIFO (Last In First Out)
The last item added is the first item removed.
Real Life Examples
• Stack of plates
• Browser history
• Undo operation
4.2 Representation of Stacks
Stack Structure
Top
↓
30
20
10
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
25
[Link](10);
[Link](20);
[Link](30);
foreach (int item in stack)
{
[Link](item);
}
}
}
4.3 Basic Operations
Stack Operations
• Push
• Pop
• Peek
• IsEmpty
4.3.1 Pop
Pop removes the top element from the stack.
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
[Link](10);
[Link](20);
int removed = [Link]();
[Link]("Removed: " + removed);
}
}
26
4.3.2 Push
Push adds an element to the top of the stack.
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
[Link](100);
[Link](200);
[Link]("Items in stack:");
foreach (int item in stack)
{
[Link](item);
}
}
}
4.4 Definition of Queues
A queue is a linear data structure that follows:
FIFO (First In First Out)
The first item added is the first item removed.
Real Life Examples
• People in a line
• Printer queue
• Ticket booking systems
27
4.5 Representation of Queues
Queue Structure
Front → 10 20 30 ← Rear
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Queue<int> queue = new Queue<int>();
[Link](10);
[Link](20);
[Link](30);
foreach (int item in queue)
{
[Link](item);
}
}
}
4.6 Basic Operations
Queue Operations
• Enqueue
• Dequeue
• Peek
• IsEmpty
4.6.1 Enqueue
Enqueue adds an element to the rear of the queue.
28
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Queue<int> queue = new Queue<int>();
[Link](5);
[Link](10);
foreach (int item in queue)
{
[Link](item);
}
}
}
4.6.2 Dequeue
Dequeue removes the front element.
C# Example
using System;
using [Link];
class Program
{
static void Main()
{
Queue<int> queue = new Queue<int>();
[Link](10);
[Link](20);
int removed = [Link]();
[Link]("Removed: " + removed);
}
}
29
4.7 Demonstration of Stack and Queues Using C
Complete Stack Example
using System;
using [Link];
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
[Link](10);
[Link](20);
[Link](30);
[Link]("Stack elements:");
foreach (int item in stack)
{
[Link](item);
}
[Link]("Popped item: " + [Link]());
}
}
Complete Queue Example
using System;
using [Link];
class Program
{
static void Main()
{
Queue<int> queue = new Queue<int>();
[Link](10);
[Link](20);
[Link](30);
[Link]("Queue elements:");
foreach (int item in queue)
{
[Link](item);
}
30
[Link]("Dequeued item: " + [Link]());
}
}
Summary
In this section, you learned:
• Linked lists and their types
• Doubly linked lists
• Circular linked lists
• Linked list operations
• Stack concepts and operations
• Queue concepts and operations
• Simple C# implementations of stacks, queues and linked lists
These data structures are important in software development, databases, operating systems and
application programming.
31
Topic 5: Search Techniques
5.1 Definition of Search
Searching is the process of finding the location of a specific target element within a collection of
data (such as an array, list, or database). The search returns either the index of the element if
found, or a value indicating its absence (like -1).
5.2 Explanation of Linear Search
Linear Search (or Sequential Search) is the simplest searching algorithm. It starts at the very
beginning of the data collection and checks each element one by one until the target element is
found or the end of the collection is reached.
Prerequisite: None. It works on both sorted and unsorted collections.
Time Complexity: $O(n)$ in the worst case, where $n$ is the number of elements.
5.3 Explanation of Binary Search
Binary Search is an efficient "divide-and-conquer" algorithm. Instead of checking every item, it
looks at the middle element of the collection:
1. If the target matches the middle element, the search is complete.
2. If the target is smaller than the middle element, the search continues in the left half.
3. If the target is larger, the search continues in the right half.
This process repeats, cutting the search space in half each time.
Prerequisite: The data collection must be sorted.
Time Complexity: $O(\log n)$ in the worst case, making it much faster than linear search for
large datasets.
5.4 Demonstration of Linear Search and Binary Search
using C#
Here is a clean, simple C# implementation demonstrating both search methods:
C#
using System;
class SearchDemo
{
static void Main()
{
// For Linear Search, data doesn't need to be sorted
int[] unsortedData = { 24, 8, 15, 42, 4, 16 };
int target1 = 42;
[Link]("--- Linear Search ---");
int linearResult = LinearSearch(unsortedData, target1);
if (linearResult != -1)
[Link]($"Element {target1} found at index:
{linearResult}");
else
[Link]($"Element {target1} not found.");
// For Binary Search, data MUST be sorted
int[] sortedData = { 4, 8, 15, 16, 24, 42 };
int target2 = 16;
[Link]("\n--- Binary Search ---");
int binaryResult = BinarySearch(sortedData, target2);
if (binaryResult != -1)
[Link]($"Element {target2} found at index:
{binaryResult}");
else
[Link]($"Element {target2} not found.");
}
// Linear Search Logic
static int LinearSearch(int[] array, int target)
{
for (int i = 0; i < [Link]; i++)
{
if (array[i] == target)
{
return i; // Element found, return its index
}
}
return -1; // Element not found
}
// Binary Search Logic
static int BinarySearch(int[] array, int target)
{
int left = 0;
int right = [Link] - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
// Check if target is present at mid
if (array[mid] == target)
return mid;
// If target is greater, ignore left half
if (array[mid] < target)
left = mid + 1;
// If target is smaller, ignore right half
else
right = mid - 1;
}
return -1; // Element not found
}
}
Topic 6: Sorting Techniques
6.1 Definition of Sorting
Sorting is the process of rearranging a collection of data into a specific logical order. This order
is typically ascending (e.g., 1 to 10, A to Z) or descending (e.g., 10 to 1, Z to A). Sorting makes
data easier to analyze and optimizes other algorithms (like Binary Search).
6.2 Categories of Sorting
Sorting algorithms are classified based on how they handle data preservation, optimization, and
memory.
Category Description
Maintains the relative order of duplicate elements. If two items have the
6.2.1 Stable Sorting
same value, their original order is preserved after sorting.
6.2.1 Unstable (Not Does not guarantee the relative order of duplicate elements; they might
Stable) be swapped during sorting.
6.2.2 Adaptive The algorithm runs faster if the input array is already partially or
Sorting completely sorted. It takes advantage of existing order.
Category Description
6.2.2 Non-Adaptive The algorithm takes the exact same amount of time/steps regardless of
Sorting the initial arrangement of the data.
6.2.3 In-Place Reorganizes elements within the original array without requiring
Sorting significant extra memory (Auxiliary Space is $O(1)$).
6.2.3 Out-of-Place Requires extra memory/temporary arrays proportional to the size of the
(Not In-Place) input data to perform the sort.
6.3 Types of Sorting Algorithms
6.3.1 Bubble Sort
Bubble Sort repeatedly steps through the list, compares adjacent elements, and swaps them if
they are in the wrong order. This causes the largest elements to "bubble up" to the end of the
array with each pass.
Type: Stable, Adaptive (if optimized), In-Place.
6.3.2 Insertion Sort
Insertion Sort works the way you might sort playing cards in your hands. It takes one element at
a time from the unsorted part and inserts it into its correct position within the already sorted part.
Type: Stable, Adaptive, In-Place.
6.3.3 Selection Sort
Selection Sort divides the array into sorted and unsorted parts. It repeatedly scans the unsorted
part to find the absolute minimum (or maximum) element, then swaps it with the first element of
the unsorted part.
Type: Unstable, Non-Adaptive, In-Place.
6.4 Demonstration of Sorting Algorithms using C#
Below is a consolidated C# program that clearly demonstrates Bubble, Insertion, and Selection
sorting algorithms using simple code loops:
C#
using System;
class SortingDemo
{
static void Main()
{
// 1. Bubble Sort Test
int[] data1 = { 64, 34, 25, 12, 22, 11, 90 };
[Link]("Original Array: " + [Link](", ", data1));
BubbleSort(data1);
[Link]("Bubble Sorted: " + [Link](", ", data1));
[Link]();
// 2. Insertion Sort Test
int[] data2 = { 64, 34, 25, 12, 22, 11, 90 };
InsertionSort(data2);
[Link]("Insertion Sorted: " + [Link](", ",
data2));
[Link]();
// 3. Selection Sort Test
int[] data3 = { 64, 34, 25, 12, 22, 11, 90 };
SelectionSort(data3);
[Link]("Selection Sorted: " + [Link](", ",
data3));
}
// 6.3.1 Bubble Sort Implementation
static void BubbleSort(int[] arr)
{
int n = [Link];
for (int i = 0; i < n - 1; i++)
{
// Track if any swap happened (makes it adaptive)
bool swapped = false;
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
// Swap adjacent elements
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// If no elements were swapped in the inner loop, array is
sorted
if (!swapped) break;
}
}
// 6.3.2 Insertion Sort Implementation
static void InsertionSort(int[] arr)
{
int n = [Link];
for (int i = 1; i < n; i++)
{
int key = arr[i];
int j = i - 1;
// Move elements of arr[0..i-1] that are greater than key
// to one position ahead of their current position
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
// 6.3.3 Selection Sort Implementation
static void SelectionSort(int[] arr)
{
int n = [Link];
for (int i = 0; i < n - 1; i++)
{
// Find the minimum element in unsorted array
int minIndex = i;
for (int j = i + 1; j < n; j++)
{
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
// Swap the found minimum element with the first element
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
}