Tutorials Logic, IN info@tutorialslogic.com

C Sorting Algorithms Bubble, Merge, Quick Sort: Tutorial, Examples, FAQs & Interview Tips

C Sorting Algorithms Bubble, Merge, Quick Sort

C in C is best learned by connecting the rule to a small command-line program. Start with the smallest function, observe the output, and then add one realistic constraint so the concept becomes practical.

The key habit for this lesson is to watch pointer, array, or file buffer as it changes. That makes the topic easier to debug, easier to explain in interviews, and easier to use in real code without memorizing isolated syntax.

Sorting Algorithms Overview

Sorting is one of the most fundamental operations in programming. Understanding how different sorting algorithms work - and their trade-offs - is essential for writing efficient C programs.

Algorithm Best Average Worst Space Stable?
Bubble Sort O(n) O(n^2) O(n^2) O(1) Yes
Selection Sort O(n^2) O(n^2) O(n^2) O(1) No
Insertion Sort O(n) O(n^2) O(n^2) O(1) Yes
Merge Sort O(n log n) O(n log n) O(n log n) O(n) Yes
Quick Sort O(n log n) O(n log n) O(n^2) O(log n) No

1. Bubble Sort

Repeatedly compares adjacent elements and swaps them if they are in the wrong order. Each pass "bubbles" the largest unsorted element to its correct position.

Bubble Sort

Bubble Sort
#include <stdio.h>

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int swapped = 0;
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // swap
                int temp  = arr[j];
                arr[j]    = arr[j + 1];
                arr[j + 1] = temp;
                swapped = 1;
            }
        }
        if (!swapped) break;  // already sorted - early exit
    }
}

void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
}

int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = 7;
    printf("Before: "); printArray(arr, n);
    bubbleSort(arr, n);
    printf("After:  "); printArray(arr, n);
    return 0;
}
// After: 11 12 22 25 34 64 90

2. Selection Sort

Finds the minimum element in the unsorted portion and places it at the beginning. Makes exactly n-1 swaps - good when writes are expensive.

Selection Sort

Selection Sort
#include <stdio.h>

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) {
            int temp    = arr[i];
            arr[i]      = arr[minIdx];
            arr[minIdx] = temp;
        }
    }
}

int main() {
    int arr[] = {29, 10, 14, 37, 13};
    int n = 5;
    selectionSort(arr, n);
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");  // 10 13 14 29 37
    return 0;
}

3. Insertion Sort

Builds the sorted array one element at a time by inserting each new element into its correct position. Very efficient for small or nearly-sorted arrays.

Insertion Sort

Insertion Sort
#include <stdio.h>

void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j   = i - 1;
        // shift elements greater than key one position right
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = 5;
    insertionSort(arr, n);
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");  // 5 6 11 12 13
    return 0;
}

4. Merge Sort

Divide-and-conquer algorithm. Splits the array in half, recursively sorts each half, then merges them. Guaranteed O(n log n) - the go-to for stable, predictable sorting.

Merge Sort

Merge Sort
#include <stdio.h>
#include <stdlib.h>

void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;

    int *L = malloc(n1 * sizeof(int));
    int *R = malloc(n2 * sizeof(int));

    for (int i = 0; i < n1; i++) L[i] = arr[left + i];
    for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];

    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) arr[k++] = L[i++];
        else               arr[k++] = R[j++];
    }
    while (i < n1) arr[k++] = L[i++];
    while (j < n2) arr[k++] = R[j++];

    free(L); free(R);
}

void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }
}

int main() {
    int arr[] = {38, 27, 43, 3, 9, 82, 10};
    int n = 7;
    mergeSort(arr, 0, n - 1);
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");  // 3 9 10 27 38 43 82
    return 0;
}

5. Quick Sort

Picks a pivot element and partitions the array so all elements less than the pivot come before it and all greater come after. Recursively sorts both partitions. Fastest in practice for most inputs.

Quick Sort

Quick Sort
#include <stdio.h>

void swap(int *a, int *b) {
    int t = *a; *a = *b; *b = t;
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];  // last element as pivot
    int i = low - 1;

    for (int j = low; j < high; j++) {
        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);
    }
}

int main() {
    int arr[] = {10, 7, 8, 9, 1, 5};
    int n = 6;
    quickSort(arr, 0, n - 1);
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");  // 1 5 7 8 9 10
    return 0;
}

Applied guide for C

Use C when the program needs a clear answer to a specific problem, not because the keyword looks familiar. In a real C task, first name the input, then name the transformation, then name the output. This small discipline shows whether the topic is being used correctly or only copied from an example.

A reliable practice flow is: create the smallest working function, add one normal case, add one edge case such as already sorted, reverse sorted, and duplicate values, and then confirm the result with compiler warnings and printed output. If the result surprises you, reduce the code until the behavior is visible again.

The most common trap here is remembering swaps without tracing comparisons. Avoid it by writing one sentence before the code that explains why C is the right choice. After the code runs, verify the lesson by doing this: count comparisons and confirm final order.

  • Identify the exact problem solved by C.
  • Trace pointer, array, or file buffer before and after the main operation.
  • Keep one intentionally broken version and explain the fix.
  • Connect the example to a small command-line program so the idea feels concrete.
Key Takeaways
  • I can explain where C fits inside a small command-line program.
  • I can point to the exact pointer, array, or file buffer affected by this topic.
  • I tested a normal case and an edge case involving already sorted, reverse sorted, and duplicate values.
  • I verified the result with compiler warnings and printed output instead of assuming it worked.
  • I can describe the main mistake: remembering swaps without tracing comparisons.
Common Mistakes to Avoid
WRONG Remembering swaps without tracing comparisons.
RIGHT Write the expected behavior first, then make the example prove it.
A one-line expectation turns the code from copied syntax into a testable idea.
WRONG Practicing only the perfect input.
RIGHT Also test already sorted, reverse sorted, and duplicate values before considering the lesson complete.
The edge case is where most interview follow-up questions begin.
WRONG Looking only at the final output.
RIGHT Trace pointer, array, or file buffer through each important step.
Tracing makes debugging faster because you can see the first incorrect state.

Practice Tasks

  • Build one small function that demonstrates C in a small command-line program.
  • Change the example to include already sorted, reverse sorted, and duplicate values and record the difference.
  • Break the example by deliberately remembering swaps without tracing comparisons, then write the corrected version.
  • Explain the finished example in five bullet points: input, operation, output, failure case, and verification.

Frequently Asked Questions

Use it when the problem matches the behavior shown in the example and when the result can be verified through compiler warnings and printed output.

Start with a tiny case, then test already sorted, reverse sorted, and duplicate values. The main warning sign is remembering swaps without tracing comparisons.

Trace pointer, array, or file buffer, predict the result, run the example, and compare your prediction with the actual output.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.