Elementary Sorting: Bubble, Selection, Insertion
প্রাথমিক সর্টিং
1. Why Study "Slow" Sorts?
Bubble, selection and insertion sort are all O(n²) — yet every CS curriculum begins with them. Why? Because they teach the deepest sorting ideas in their simplest form: invariants, swaps, comparisons, stability. Modern hybrid algorithms like Tim sort still call insertion sort underneath.
Insertion sort প্রায়-sorted ডেটায় O(n) — তাই hybrid sort-এর ভিত্তি এটিই।
2. Bubble Sort — Adjacent Swaps
Walk through the array, comparing each pair of adjacent elements. If they're out of order, swap. After one full pass, the largest element has "bubbled" to the end. Repeat. Invariant after k passes: the last k elements are in their final positions.
3. The Three Sorts in One Program
Below we implement all three sorts and count the swaps each performs. Notice how on a nearly-sorted array, insertion sort is dramatically faster.
#include <bits/stdc++.h>
using namespace std;
long long bubbleSort(vector<int> a) {
long long swaps = 0;
int n = a.size();
for (int i = 0; i < n - 1; i++) {
bool moved = false;
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j+1]) { swap(a[j], a[j+1]); swaps++; moved = true; }
}
if (!moved) break; // already sorted — early exit
}
return swaps;
}
long long selectionSort(vector<int> a) {
long long swaps = 0;
int n = a.size();
for (int i = 0; i < n - 1; i++) {
int mn = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[mn]) mn = j;
if (mn != i) { swap(a[i], a[mn]); swaps++; }
}
return swaps;
}
long long insertionSort(vector<int> a) {
long long shifts = 0;
int n = a.size();
for (int i = 1; i < n; i++) {
int key = a[i], j = i - 1;
while (j >= 0 && a[j] > key) { a[j+1] = a[j]; j--; shifts++; }
a[j+1] = key;
}
return shifts;
}
int main() {
vector<int> random_data = {5, 2, 9, 1, 7, 3, 8, 4, 6};
vector<int> nearly = {1, 2, 3, 4, 6, 5, 7, 8, 9};
cout << "-- random --\n";
cout << "bubble swaps = " << bubbleSort(random_data) << "\n";
cout << "selection swaps = " << selectionSort(random_data) << "\n";
cout << "insertion shifts = " << insertionSort(random_data) << "\n\n";
cout << "-- nearly sorted --\n";
cout << "bubble swaps = " << bubbleSort(nearly) << "\n";
cout << "selection swaps = " << selectionSort(nearly) << "\n";
cout << "insertion shifts = " << insertionSort(nearly) << "\n";
return 0;
}
4. Selection Sort — Why It Works
Loop invariant: after iteration i, the prefix a[0..i] contains the
i+1 smallest elements in sorted order. We prove this by induction:
Base. Before iteration 0, the empty prefix is trivially sorted.
Step. Assume the prefix
a[0..i-1] contains the i smallest values, sorted.
Iteration i picks the minimum of the suffix a[i..n-1] — which is the
(i+1)-th smallest overall — and places it at position i. The new prefix
a[0..i] now contains the i+1 smallest, sorted. ∎
i-এর পরে prefix a[0..i]-তে i+1-টি
ছোট element sorted অবস্থায় থাকে। induction দিয়ে প্রমাণ — base খালি prefix থেকে শুরু, প্রতি ধাপে next minimum-কে
সঠিক জায়গায় বসানো হয়।
Selection sort always does exactly n-1 swaps — much fewer than bubble sort's worst case.
That makes it useful when writes to memory are expensive (e.g., flash storage).
5. Insertion Sort — The Hidden Hero
Imagine sorting playing cards in your hand. You pick a new card and slide it left until it's in the right spot. That is insertion sort — and it has remarkable properties:
- Adaptive: O(n) on already-sorted input, O(n + d) where d = number of inversions.
- Stable: equal keys keep their relative order.
- In-place: needs only O(1) extra memory.
- Online: can sort a stream as data arrives.
6. Stability — Why Insertion Sort Beats Selection
A sort is stable if records with equal keys appear in the output in the same order as in the input. This matters when you sort by one field after sorting by another.
#include <bits/stdc++.h>
using namespace std;
// Each item = (key, original_index)
using Item = pair<int, int>;
void selectionSort(vector<Item>& a) {
int n = a.size();
for (int i = 0; i < n - 1; i++) {
int mn = i;
for (int j = i + 1; j < n; j++)
if (a[j].first < a[mn].first) mn = j;
swap(a[i], a[mn]);
}
}
void insertionSort(vector<Item>& a) {
int n = a.size();
for (int i = 1; i < n; i++) {
Item key = a[i]; int j = i - 1;
while (j >= 0 && a[j].first > key.first) { a[j+1] = a[j]; j--; }
a[j+1] = key;
}
}
int main() {
vector<Item> data = {{3,0},{1,1},{3,2},{2,3},{3,4}};
auto A = data; selectionSort(A);
cout << "selection: ";
for (auto& p : A) cout << "(" << p.first << "," << p.second << ") ";
cout << "\n";
auto B = data; insertionSort(B);
cout << "insertion: ";
for (auto& p : B) cout << "(" << p.first << "," << p.second << ") ";
cout << "\n";
return 0;
}
7. Side-by-Side Comparison
| Algorithm | Best | Average | Worst | Stable? | In-place? |
|---|---|---|---|---|---|
| Bubble sort | O(n) | O(n²) | O(n²) | Yes | Yes |
| Selection sort | O(n²) | O(n²) | O(n²) | No | Yes |
| Insertion sort | O(n) | O(n²) | O(n²) | Yes | Yes |
Insertion sort wins when (কখন)
- Data is nearly sorted
- n is small (≤ 50)
- Streaming data (online)
- Hybrid sort fallback
Selection sort wins when (কখন)
- Memory writes are expensive
- You only need n-1 swaps max
- When key comparisons are cheap, but writes (e.g. swapping huge structs) are not
8. Practice Problems
Try first; reveal the runnable answer when you're stuck.
-
Sort the array and report the total number of swaps bubble sort performs.array sort করে bubble sort-এর মোট swap সংখ্যা বের করুন।
✨ Show Answer (উত্তর দেখুন)
bubble_swaps.cpp#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a={5,2,8,1,4}; long long sw=0; for(int i=0;i<(int)a.size()-1;i++) for(int j=0;j<(int)a.size()-1-i;j++) if(a[j]>a[j+1]){swap(a[j],a[j+1]);sw++;} cout<<"swaps = "<<sw<<"\n"; for(int x:a) cout<<x<<" "; cout<<"\n"; } -
Bubble sort with early termination: stop when a pass makes no swap.যদি কোনো pass-এ একটিও swap না হয়, bubble sort বন্ধ করুন।
✨ Show Answer (উত্তর দেখুন)
bubble_early.cpp#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a={1,2,3,5,4}; int n=a.size(), passes=0; for(int i=0;i<n-1;i++){ bool moved=false; passes++; for(int j=0;j<n-1-i;j++) if(a[j]>a[j+1]){swap(a[j],a[j+1]);moved=true;} if(!moved) break; } cout<<"passes used = "<<passes<<"\n"; } -
Sort an array where every element is at most k positions from its sorted location (use insertion sort).এমন array sort করুন যেখানে প্রতিটি element সর্বাধিক k পজিশন দূরে আছে।
✨ Show Answer (উত্তর দেখুন)
k_sorted.cpp#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a={2,1,3,5,4,6}; // k = 1 int n=a.size(); for(int i=1;i<n;i++){ int key=a[i], j=i-1; while(j>=0 && a[j]>key){a[j+1]=a[j];j--;} a[j+1]=key; } for(int x:a) cout<<x<<" "; cout<<"\n"; } -
Stable sort a list of
(name, age)first by name, then by age — using insertion sort twice.(name, age) list-কে আগে name, পরে age দিয়ে stable sort করুন।✨ Show Answer (উত্তর দেখুন)
multi_sort.cpp#include <bits/stdc++.h> using namespace std; using P = pair<string,int>; template<class Cmp> void isort(vector<P>& a, Cmp cmp){ for(int i=1;i<(int)a.size();i++){ P k=a[i]; int j=i-1; while(j>=0 && cmp(k,a[j])){a[j+1]=a[j];j--;} a[j+1]=k; } } int main(){ vector<P> v={{"Karim",25},{"Anika",30},{"Karim",22},{"Anika",28}}; isort(v, [](const P& a, const P& b){ return a.second < b.second; }); isort(v, [](const P& a, const P& b){ return a.first < b.first; }); for(auto& p:v) cout<<p.first<<" "<<p.second<<"\n"; } -
Modify selection sort to find the min and max together — fewer comparisons.selection sort পরিবর্তন করুন যাতে min ও max একসাথে খুঁজে — কম comparison হয়।
✨ Show Answer (উত্তর দেখুন)
double_select.cpp#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a={5,2,9,1,7,3}; int lo=0, hi=a.size()-1; while(lo<hi){ int mn=lo, mx=lo; for(int j=lo;j<=hi;j++){ if(a[j]<a[mn]) mn=j; if(a[j]>a[mx]) mx=j; } swap(a[lo],a[mn]); if(mx==lo) mx=mn; // the max moved! swap(a[hi],a[mx]); lo++; hi--; } for(int x:a) cout<<x<<" "; cout<<"\n"; } -
Use insertion sort with binary search to find the insertion point (binary-insertion sort).insertion sort-এ insertion point খুঁজতে binary search ব্যবহার করুন।
✨ Show Answer (উত্তর দেখুন)
bin_insert.cpp#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a={5,2,9,1,7,3}; int n=a.size(); for(int i=1;i<n;i++){ int key=a[i]; int pos = upper_bound(a.begin(), a.begin()+i, key) - a.begin(); for(int j=i;j>pos;j--) a[j]=a[j-1]; a[pos]=key; } for(int x:a) cout<<x<<" "; cout<<"\n"; }
Summary — Module 12
All three sorts run in O(n²) — yet each shines in its own situation. Bubble sort detects already-sorted data via early termination. Selection sort minimises swaps. Insertion sort is adaptive, stable, in-place, online — and that is why every modern hybrid sort calls it for small partitions.