DSA
Sorting Algorithms: Bubble, Selection, and Insertion Sort
2026-08-2910 min read
Sorting Algorithms
Sorting means arranging elements in a particular order.
For example:
Before:
[5, 2, 8, 1, 3]
After:
[1, 2, 3, 5, 8]
There are many sorting algorithms. Here we will look at three basic ones:
Bubble Sort
Selection Sort
Insertion Sort
The important thing is to understand how each algorithm works instead of just memorizing the code.
1. Bubble Sort
What is Bubble Sort?
Bubble Sort compares two elements next to each other.
If they are in the wrong order, they are swapped.
For example:
[5, 3, 8, 4]
Compare 5 and 3
5 > 3
Swap them:
[3, 5, 8, 4]
Then we compare the next pair:
[3, 5, 8, 4]
Compare 5 and 8
5 < 8
No swap.
Then:
[3, 5, 8, 4]
Compare 8 and 4
8 > 4
Swap:
[3, 5, 4, 8]
After one complete pass, the largest element has moved to the end.
[3, 5, 4, 8]
^
largest
This is where the name Bubble Sort comes from. Large elements keep moving toward the end of the array.
How Bubble Sort works
Suppose we have:
[5, 1, 4, 2, 8]
First pass
Compare 5 and 1:
[1, 5, 4, 2, 8]
Compare 5 and 4:
[1, 4, 5, 2, 8]
Compare 5 and 2:
[1, 4, 2, 5, 8]
Compare 5 and 8:
[1, 4, 2, 5, 8]
Now 8 is in its correct position.
Second pass
We don't need to check 8 again.
[1, 4, 2, 5 | 8]
Compare 1 and 4:
[1, 4, 2, 5 | 8]
Compare 4 and 2:
[1, 2, 4, 5 | 8]
Compare 4 and 5:
[1, 2, 4, 5 | 8]
Now both 5 and 8 are in the correct positions.
Continue until the whole array is sorted.
Final result:
[1, 2, 4, 5, 8]
Bubble Sort code
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
let swapped = false;
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
if (!swapped) {
break;
}
}
return arr;
}
Why do we use swapped?
Consider an already sorted array:
[1, 2, 3, 4, 5]
There is nothing to swap.
Without the swapped check, Bubble Sort would continue making unnecessary passes.
With the check:
No swap happened
|
v
Array is already sorted
|
v
Stop
This improves the best case from O(n²) to O(n).
Time and space complexity
Case Complexity
Best case O(n)
Average case O(n²)
Worst case O(n²)
Space O(1)
The O(n) best case assumes the early-stop optimization is used.
When should you use Bubble Sort?
Bubble Sort is mainly useful for learning.
It is easy to understand and is a good example for learning:
Comparisons
Swapping
Nested loops
Time complexity
It is generally not a good choice for large datasets.
Remember
Bubble Sort
Compare neighbors
↓
Swap if they are in the wrong order
↓
Largest element moves to the end
↓
Repeat
2. Selection Sort
What is Selection Sort?
Selection Sort works by finding the smallest element and putting it in the correct position.
For example:
[5, 3, 8, 1, 4]
First, find the smallest element.
Smallest = 1
Put 1 at the beginning:
[1, 3, 8, 5, 4]
Now we don't need to worry about 1.
Look at the remaining elements:
[1 | 3, 8, 5, 4]
Find the smallest:
3
It is already in the correct position.
Then look at:
[1, 3 | 8, 5, 4]
The smallest is 4.
Put it in the correct position:
[1, 3, 4, 5, 8]
The array is sorted.
The main idea
Selection Sort divides the array into two parts:
Sorted | Unsorted
At the beginning:
[] | [5, 3, 8, 1, 4]
After the first pass:
[1] | [3, 8, 5, 4]
After the second pass:
[1, 3] | [8, 5, 4]
After the third pass:
[1, 3, 4] | [8, 5]
Eventually:
[1, 3, 4, 5, 8] | []
Step-by-step example
Let's sort:
[64, 25, 12, 22, 11]
First pass
Start at index 0.
Find the smallest element:
64, 25, 12, 22, 11
^
smallest
Smallest is 11.
Swap 64 and 11:
[11, 25, 12, 22, 64]
11 is now fixed.
Second pass
Ignore the first element.
[11 | 25, 12, 22, 64]
Smallest in the remaining part is 12.
Swap:
[11, 12, 25, 22, 64]
Third pass
[11, 12 | 25, 22, 64]
Smallest is 22.
Swap:
[11, 12, 22, 25, 64]
Fourth pass
[11, 12, 22 | 25, 64]
Smallest is already 25.
The array is sorted:
[11, 12, 22, 25, 64]
Selection Sort code
function selectionSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
return arr;
}
Why do we use minIndex?
We don't immediately swap every time we find a smaller value.
Instead, we remember where the smallest value is.
Example:
[7, 4, 5, 2, 6]
Start:
minIndex = 0
minimum = 7
Check 4:
4 < 7
minimum = 4
Check 5:
5 < 4?
No.
Check 2:
2 < 4
minimum = 2
Check 6:
6 < 2?
No.
At the end:
minimum = 2
Now swap it with the first element.
[2, 4, 5, 7, 6]
This is the main idea behind Selection Sort:
Find minimum
↓
Remember its position
↓
Swap once
Time and space complexity
Case Complexity
Best case O(n²)
Average case O(n²)
Worst case O(n²)
Space O(1)
Even if the array is already sorted, Selection Sort still needs to search the remaining elements to find the minimum.
For example:
[1, 2, 3, 4, 5]
It still checks the remaining elements on every pass.
One useful property
Selection Sort does relatively few swaps.
It performs at most around n - 1 swaps.
So while it makes many comparisons, it doesn't constantly swap elements.
When should you use Selection Sort?
Selection Sort is mainly useful for:
Learning sorting
Understanding the minimum-selection pattern
Understanding how to separate sorted and unsorted parts
Situations where the number of swaps matters
For large datasets, it is usually not the best choice.
Remember
Selection Sort
Find the smallest element
↓
Put it at the current position
↓
Move to the next position
↓
Repeat
3. Insertion Sort
What is Insertion Sort?
Insertion Sort works in a similar way to arranging playing cards in your hand.
Suppose you have:
[2, 5, 8]
Now you get the number:
4
Where should 4 go?
Between 2 and 5:
[2, 4, 5, 8]
That is the basic idea of Insertion Sort.
You take one element at a time and insert it into the correct position in the already sorted part.
The main idea
Insertion Sort also divides the array into two parts:
Sorted | Unsorted
For example:
[2, 4, 5 | 8, 1, 7]
The left side is already sorted.
Take 8:
[2, 4, 5 | 8]
Since 8 is greater than 5, it can stay where it is.
Now take 1.
We need to move larger elements to the right:
[2, 4, 5, 8 | 1]
Move 8:
[2, 4, 5, 8, 8]
Move 5:
[2, 4, 5, 5, 8]
Move 4:
[2, 4, 4, 5, 8]
Move 2:
[2, 2, 4, 5, 8]
Now insert 1:
[1, 2, 4, 5, 8]
Step-by-step example
Let's sort:
[5, 2, 4, 6, 1, 3]
Start
The first element is considered sorted:
[5 | 2, 4, 6, 1, 3]
Insert 2
Compare 2 with 5.
2 < 5
Move 5 to the right:
[5, 5, 4, 6, 1, 3]
Insert 2:
[2, 5, 4, 6, 1, 3]
Now:
[2, 5 | 4, 6, 1, 3]
Insert 4
Compare 4 with 5.
4 < 5
Move 5:
[2, 5, 5, 6, 1, 3]
Now compare 4 with 2.
4 > 2
Stop and insert 4:
[2, 4, 5, 6, 1, 3]
Insert 6
6 is already greater than 5.
So:
[2, 4, 5, 6, 1, 3]
Insert 1
Everything before 1 is greater than it.
Move:
6 → right
5 → right
4 → right
2 → right
Then insert 1:
[1, 2, 4, 5, 6, 3]
Insert 3
Compare 3 with 6:
6 > 3
Move 6.
Compare 3 with 5:
5 > 3
Move 5.
Compare 3 with 4:
4 > 3
Move 4.
Compare 3 with 2:
2 < 3
Stop.
Insert 3:
[1, 2, 3, 4, 5, 6]
Sorted.
Insertion Sort code
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
const key = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
return arr;
}
What does key mean?
key is the element we are currently trying to place.
For example:
[2, 4, 7 | 5]
Here:
key = 5
We want to find the correct position for 5.
We compare it with elements on the left and shift larger elements.
Eventually:
[2, 4, 5, 7]
Why is Insertion Sort good for nearly sorted arrays?
Consider:
[1, 2, 3, 5, 4]
Only 4 is out of place.
Insertion Sort doesn't need to rearrange the entire array.
It simply moves 5 and inserts 4:
[1, 2, 3, 4, 5]
This is why Insertion Sort can be useful when the data is already mostly sorted.
Time and space complexity
Case Complexity
Best case O(n)
Average case O(n²)
Worst case O(n²)
Space O(1)
Best case
Already sorted:
[1, 2, 3, 4, 5]
Very little shifting is needed.
Time:
O(n)
Worst case
Reverse sorted:
[5, 4, 3, 2, 1]
Almost every element needs to move.
Time:
O(n²)
When should you use Insertion Sort?
Insertion Sort is useful when:
The array is small.
The array is already mostly sorted.
You want a simple in-place sorting algorithm.
You are learning how insertion and shifting work.
Among these three basic algorithms, Insertion Sort is often the most useful in practice for small or nearly sorted data.
Remember
Insertion Sort
Take one element
↓
Compare it with the sorted part
↓
Move larger elements right
↓
Insert the element
↓
Repeat
Bubble Sort vs Selection Sort vs Insertion Sort
Feature Bubble Sort Selection Sort Insertion Sort
Main idea Compare neighbors Find minimum Insert into sorted part
Best case O(n) O(n²) O(n)
Average case O(n²) O(n²) O(n²)
Worst case O(n²) O(n²) O(n²)
Space O(1) O(1) O(1)
Stable Yes Usually no Yes
In-place Yes Yes Yes
Good for nearly sorted data Not usually No Yes
How to Identify the Algorithm
When reading a question, look for these patterns.
If you see adjacent comparisons
Think:
Bubble Sort
Example:
arr[j] and arr[j + 1]
The algorithm is comparing neighbors.
If you see minimum selection
Think:
Selection Sort
Typical pattern:
minIndex = i
Find the smallest element
Swap it with arr[i]
If you see shifting and inserting
Think:
Insertion Sort
Typical pattern:
key = arr[i]
Move larger elements to the right
Insert key
Quick Revision
Bubble Sort
Compare adjacent elements
Swap when needed
Largest element moves to the end
Time:
Best: O(n)
Average: O(n²)
Worst: O(n²)
Space: O(1)
Selection Sort
Find the minimum
Swap it with the current position
Repeat
Time:
Best: O(n²)
Average: O(n²)
Worst: O(n²)
Space: O(1)
Insertion Sort
Take one element
Find where it belongs
Shift larger elements
Insert it
Time:
Best: O(n)
Average: O(n²)
Worst: O(n²)
Space: O(1)
Final Takeaway
The easiest way to remember these three algorithms is:
Bubble Sort
→ Compare neighbors
Selection Sort
→ Find the minimum
Insertion Sort
→ Insert into the sorted part
All three can sort an array, but they work differently.
For learning DSA, understanding these differences is more important than memorizing the code.
A useful way to think about them is:
Bubble:
"Are these two next to each other in the right order?"
Selection:
"What is the smallest element left?"
Insertion:
"Where should this element be inserted?"
Once these three ideas are clear, the implementation becomes much easier to remember.