概述

本文整理常见排序算法,每种算法包含原理说明、逐步示例、时间空间复杂度及 Python、C/C++ 实现。统一示例数组为 $[5, 2, 8, 1, 9, 3]$,目标升序。

算法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性
冒泡排序 $O(n^2)$ $O(n^2)$ $O(n)$ $O(1)$ 稳定
选择排序 $O(n^2)$ $O(n^2)$ $O(n^2)$ $O(1)$ 不稳定
插入排序 $O(n^2)$ $O(n^2)$ $O(n)$ $O(1)$ 稳定
希尔排序 $O(n^{1.3})$ $O(n^2)$ $O(n)$ $O(1)$ 不稳定
归并排序 $O(n\log n)$ $O(n\log n)$ $O(n\log n)$ $O(n)$ 稳定
快速排序 $O(n\log n)$ $O(n^2)$ $O(n\log n)$ $O(\log n)$ 不稳定
堆排序 $O(n\log n)$ $O(n\log n)$ $O(n\log n)$ $O(1)$ 不稳定
计数排序 $O(n+k)$ $O(n+k)$ $O(n+k)$ $O(k)$ 稳定
桶排序 $O(n+k)$ $O(n^2)$ $O(n+k)$ $O(n+k)$ 稳定
基数排序 $O(n \cdot k)$ $O(n \cdot k)$ $O(n \cdot k)$ $O(n+k)$ 稳定

其中 $k$ 为数值范围(计数/桶)或位数(基数)。


冒泡排序 (Bubble Sort)

原理

相邻元素两两比较,若前者大于后者则交换,使较大元素逐步“冒泡”到末尾。每轮确定一个最大值的位置。

逐步示例

冒泡排序示例

数组 $[5, 2, 8, 1, 9, 3]$:

第 1 轮(比较到倒数第 1 个):

  • 5 vs 2 → 交换 → $[2, 5, 8, 1, 9, 3]$
  • 5 vs 8 → 不换 → $[2, 5, 8, 1, 9, 3]$
  • 8 vs 1 → 交换 → $[2, 5, 1, 8, 9, 3]$
  • 8 vs 9 → 不换 → $[2, 5, 1, 8, 9, 3]$
  • 9 vs 3 → 交换 → $[2, 5, 1, 8, 3, \mathbf{9}]$(9 已到位)

第 2 轮(从 $[2, 5, 1, 8, 3, 9]$ 开始,比较到倒数第 2 个):

  • 2 vs 5 → 不换 → $[2, 5, 1, 8, 3, 9]$
  • 5 vs 1 → 交换 → $[2, 1, 5, 8, 3, 9]$
  • 5 vs 8 → 不换 → $[2, 1, 5, 8, 3, 9]$
  • 8 vs 3 → 交换 → $[2, 1, 5, 3, \mathbf{8}, \mathbf{9}]$

第 3 轮(从 $[2, 1, 5, 3, 8, 9]$ 开始):

  • 2 vs 1 → 交换 → $[1, 2, 5, 3, 8, 9]$
  • 2 vs 5 → 不换 → $[1, 2, 5, 3, 8, 9]$
  • 5 vs 3 → 交换 → $[1, 2, 3, \mathbf{5}, \mathbf{8}, \mathbf{9}]$

第 4 轮:1 vs 2、2 vs 3 均不换,已有序 → $[\mathbf{1}, \mathbf{2}, \mathbf{3}, \mathbf{5}, \mathbf{8}, \mathbf{9}]$,完成。

复杂度

  • 时间:最好 $O(n)$(已序),平均/最坏 $O(n^2)$
  • 空间:$O(1)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
def bubble_sort(arr):
n = len(arr)
for i in range(n - 1):
swapped = False
for j in range(n - 1 - i):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
if not swapped:
break
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void bubble_sort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int swapped = 0;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
swapped = 1;
}
}
if (!swapped) break;
}
}

选择排序 (Selection Sort)

原理

每轮在未排序区间选最小元素,与未排序区首元素交换,使有序区间逐步扩大。

逐步示例

选择排序示例

数组 $[5, 2, 8, 1, 9, 3]$:

第 1 轮:未排序 $[5, 2, 8, 1, 9, 3]$,最小 1,与 5 交换 → $[\mathbf{1}, 2, 8, 5, 9, 3]$

第 2 轮:未排序 $[2, 8, 5, 9, 3]$,最小 2,已在首位 → $[\mathbf{1}, \mathbf{2}, 8, 5, 9, 3]$

第 3 轮:未排序 $[8, 5, 9, 3]$,最小 3,与 8 交换 → $[\mathbf{1}, \mathbf{2}, \mathbf{3}, 5, 9, 8]$

第 4 轮:未排序 $[5, 9, 8]$,最小 5,已在首位 → $[\mathbf{1}, \mathbf{2}, \mathbf{3}, \mathbf{5}, 9, 8]$

第 5 轮:未排序 $[9, 8]$,最小 8,与 9 交换 → $[\mathbf{1}, \mathbf{2}, \mathbf{3}, \mathbf{5}, \mathbf{8}, \mathbf{9}]$,完成。

复杂度

  • 时间:$O(n^2)$(始终 $n(n-1)/2$ 次比较)
  • 空间:$O(1)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
def selection_sort(arr):
n = len(arr)
for i in range(n - 1):
min_idx = i
for j in range(i + 1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
void selection_sort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int min_idx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx])
min_idx = j;
}
int tmp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = tmp;
}
}

插入排序 (Insertion Sort)

原理

将数组分为有序区与无序区,每次取无序区首个元素,在有序区中从后往前找插入位置并插入。

逐步示例

插入排序示例

数组 $[5, 2, 8, 1, 9, 3]$,初始有序区为 $[5]$:

插入 2:5 > 2,5 后移,插入 → $[\mathbf{2}, \mathbf{5}, 8, 1, 9, 3]$

插入 8:5 < 8,直接插在 5 后 → $[\mathbf{2}, \mathbf{5}, \mathbf{8}, 1, 9, 3]$

插入 1:8、5、2 均 > 1,依次后移,1 插入首位 → $[\mathbf{1}, \mathbf{2}, \mathbf{5}, \mathbf{8}, 9, 3]$

插入 9:8 < 9,直接插在 8 后 → $[\mathbf{1}, \mathbf{2}, \mathbf{5}, \mathbf{8}, \mathbf{9}, 3]$

插入 3:9、8、5 > 3,2 < 3,3 插入 2 与 5 之间 → $[\mathbf{1}, \mathbf{2}, \mathbf{3}, \mathbf{5}, \mathbf{8}, \mathbf{9}]$,完成。

复杂度

  • 时间:最好 $O(n)$(已序),平均/最坏 $O(n^2)$
  • 空间:$O(1)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
def insertion_sort(arr):
n = len(arr)
for i in range(1, n):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
void insertion_sort(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;
}
}

希尔排序 (Shell Sort)

原理

插入排序的改进:按递减步长 $h$ 分组(如 $n/2, n/4, \ldots, 1$),对每组做插入排序。步长 1 时等价于普通插入排序。

逐步示例

希尔排序示例

数组 $[5, 2, 8, 1, 9, 3]$,$n=6$,步长序列 3, 1:

步长 3:分为 $(5,1), (2,9), (8,3)$

  • $(5,1)$ → $(1, 5)$:$[1, 2, 8, 5, 9, 3]$
  • $(2,9)$ → $(2, 9)$:$[1, 2, 8, 5, 9, 3]$
  • $(8,3)$ → $(3, 8)$:$[1, 2, 3, 5, 9, 8]$
  • 结果:$[1, 2, 3, 5, 9, 8]$(注意 9、8 未交换)

步长 1:对 $[1, 2, 3, 5, 9, 8]$ 做插入排序,插入 8 时 9 后移 → $[1, 2, 3, 5, 8, 9]$,完成。

复杂度

  • 时间:平均约 $O(n^{1.3})$(依赖步长),最坏 $O(n^2)$,最好 $O(n)$
  • 空间:$O(1)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
def shell_sort(arr):
n = len(arr)
gap = n // 2
while gap > 0:
for i in range(gap, n):
key = arr[i]
j = i
while j >= gap and arr[j - gap] > key:
arr[j] = arr[j - gap]
j -= gap
arr[j] = key
gap //= 2
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
void shell_sort(int arr[], int n) {
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int key = arr[i];
int j = i;
while (j >= gap && arr[j - gap] > key) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = key;
}
}
}

归并排序 (Merge Sort)

原理

分治:将数组二分,分别递归排序,再将两个有序子数组合并。合并时用双指针比较两个子数组头部,取较小者放入结果。

逐步示例

归并排序示例

数组 $[5, 2, 8, 1, 9, 3]$:

分解:$[5,2,8] | [1,9,3]$ → $[5,2]|[8] | [1,9]|[3]$ → $[5]|[2]|[8]|[1]|[9]|[3]$

合并

  • $[5],[2]$ → $[2,5]$
  • $[2,5],[8]$ → $[2,5,8]$
  • $[1],[9]$ → $[1,9]$
  • $[1,9],[3]$ → $[1,3,9]$
  • $[2,5,8],[1,3,9]$:双指针,1→2→3→5→8→9 → $[1,2,3,5,8,9]$,完成。

复杂度

  • 时间:$O(n\log n)$(分治深度 $\log n$,每层合并 $O(n)$)
  • 空间:$O(n)$(辅助数组)

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def merge(arr, left, mid, right):
L = arr[left:mid + 1]
R = arr[mid + 1:right + 1]
i = j = 0
k = left
while i < len(L) and j < len(R):
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1

def merge_sort(arr, left=0, right=None):
if right is None:
right = len(arr) - 1
if left >= right:
return
mid = (left + right) // 2
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
merge(arr, left, mid, right)
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
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++];
}

void merge_sort(int arr[], int left, int right) {
if (left >= right) return;
int mid = (left + right) / 2;
merge_sort(arr, left, mid);
merge_sort(arr, mid + 1, right);
merge(arr, left, mid, right);
}

快速排序 (Quick Sort)

原理

选一个基准(通常取首/尾/中),将小于基准的放左侧,大于的放右侧,再对左右子区间递归排序。

逐步示例(以末位为基准)

快速排序示例

数组 $[5, 2, 8, 1, 9, 3]$,基准 = 3:

分区(Lomuto,基准=3):

  • j=0: 5>3 不换;j=1: 2≤3 换 → $[2, 5, 8, 1, 9, 3]$
  • j=2: 8>3 不换;j=3: 1≤3 换 → $[2, 1, 8, 5, 9, 3]$
  • j=4: 9>3 不换;最后 pivot 归位 → $[2, 1, \mathbf{3}, 5, 9, 8]$,3 在索引 2

左子 $[2, 1]$:基准 1,分区 → $[\mathbf{1}, \mathbf{2}]$

右子 $[5, 9, 8]$:基准 8,分区 → $[5, \mathbf{8}, 9]$;$[5]$、$[9]$ 已有序

合并:$[1, 2, 3, 5, 8, 9]$,完成。

复杂度

  • 时间:平均 $O(n\log n)$,最坏 $O(n^2)$(基准总是最值),最好 $O(n\log n)$
  • 空间:$O(\log n)$(递归栈)

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def partition(arr, low, high):
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
return i + 1

def quick_sort(arr, low=0, high=None):
if high is None:
high = len(arr) - 1
if low < high:
pi = partition(arr, low, high)
quick_sort(arr, low, pi - 1)
quick_sort(arr, pi + 1, high)
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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];
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 quick_sort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quick_sort(arr, low, pi - 1);
quick_sort(arr, pi + 1, high);
}
}

堆排序 (Heap Sort)

原理

用数组表示大顶堆:父节点 ≥ 子节点。反复取堆顶(最大值)与末尾交换,堆大小减 1,再对根做下沉(heapify),直到堆为空。

逐步示例(简略)

堆排序示例

数组 $[5, 2, 8, 1, 9, 3]$ 建大顶堆:

建堆:从最后一个非叶节点起,自底向上做下沉。

  • 初始树:5 为根,左子 2、右子 8;2 子 1、9;8 子 3
  • i=2 下沉 (8,3):无;i=1 下沉 (2,1,9):9 上浮 → $[5, 9, 8, 1, 2, 3]$
  • i=0 下沉 (5,9,8):9 上浮 → $[9, 5, 8, 1, 2, 3]$

排序(每次交换堆顶与堆尾,再对堆区下沉):

  1. 9↔3 → $[3, 5, 8, 1, 2 | 9]$,下沉 → $[8, 5, 3, 1, 2 | 9]$
  2. 8↔2 → $[2, 5, 3, 1 | 8, 9]$,下沉 → $[5, 2, 3, 1 | 8, 9]$
  3. 5↔1 → $[1, 2, 3 | 5, 8, 9]$,下沉 → $[3, 2, 1 | 5, 8, 9]$
  4. 3↔1 → $[1, 2 | 3, 5, 8, 9]$,下沉 → $[2, 1 | 3, 5, 8, 9]$
  5. 2↔1 → $[1 | 2, 3, 5, 8, 9]$,完成

复杂度

  • 时间:$O(n\log n)$(建堆 $O(n)$,$n$ 次取顶+下沉 $O(\log n)$)
  • 空间:$O(1)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)

def heap_sort(arr):
n = len(arr)
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
heapify(arr, i, 0)
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i) {
int tmp = arr[i];
arr[i] = arr[largest];
arr[largest] = tmp;
heapify(arr, n, largest);
}
}

void heap_sort(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n - 1; i > 0; i--) {
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
heapify(arr, i, 0);
}
}

计数排序 (Counting Sort)

原理

适用于整数且范围 $[0, k]$ 较小的情况。统计每个值出现次数,再按值顺序回填到原数组。

逐步示例

计数排序示例

数组 $[5, 2, 8, 1, 9, 3]$,假设范围 $[0, 9]$:

计数:count = [0,1,1,1,0,1,0,0,1,1](1 出现 1 次,2 出现 1 次,…)

前缀和(或直接累加回填):count = [0,1,2,3,3,4,4,4,5,6]

回填(从后往前保证稳定):

  • 3 → 位置 2 → $[?, ?, 3, ?, ?, ?]$
  • 9 → 位置 5 → $[?, ?, 3, ?, ?, 9]$
  • 1 → 位置 0 → $[1, ?, 3, ?, ?, 9]$
  • 8 → 位置 4 → $[1, ?, 3, ?, 8, 9]$
  • 2 → 位置 1 → $[1, 2, 3, ?, 8, 9]$
  • 5 → 位置 3 → $[1, 2, 3, 5, 8, 9]$,完成。

复杂度

  • 时间:$O(n + k)$
  • 空间:$O(k)$(计数数组)

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def counting_sort(arr, max_val=None):
if max_val is None:
max_val = max(arr)
count = [0] * (max_val + 1)
for x in arr:
count[x] += 1
for i in range(1, max_val + 1):
count[i] += count[i - 1]
output = [0] * len(arr)
for x in reversed(arr):
output[count[x] - 1] = x
count[x] -= 1
for i in range(len(arr)):
arr[i] = output[i]
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
void counting_sort(int arr[], int n, int max_val) {
int count[max_val + 1];
for (int i = 0; i <= max_val; i++) count[i] = 0;
for (int i = 0; i < n; i++) count[arr[i]]++;
for (int i = 1; i <= max_val; i++) count[i] += count[i - 1];
int output[n];
for (int i = n - 1; i >= 0; i--) {
output[count[arr[i]] - 1] = arr[i];
count[arr[i]]--;
}
for (int i = 0; i < n; i++) arr[i] = output[i];
}

桶排序 (Bucket Sort)

原理

将值域分成若干桶,把元素按值放入对应桶,对每个桶内部排序(通常用插入排序),再按桶顺序依次输出。

逐步示例

桶排序示例

数组 $[5, 2, 8, 1, 9, 3]$,范围 $[0, 10)$,设 5 个桶,每桶区间长度 2:

  • 桶 0 [0,2):1
  • 桶 1 [2,4):2, 3
  • 桶 2 [4,6):5
  • 桶 3 [6,8):空
  • 桶 4 [8,10):8, 9

各桶内排序后依次输出:1, 2, 3, 5, 8, 9,完成。

复杂度

  • 时间:平均 $O(n+k)$,最坏 $O(n^2)$(元素集中到少数桶)
  • 空间:$O(n+k)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def bucket_sort(arr, bucket_count=5):
if not arr:
return arr
min_val, max_val = min(arr), max(arr)
bucket_range = (max_val - min_val) / bucket_count + 1e-9
buckets = [[] for _ in range(bucket_count)]
for x in arr:
idx = min(int((x - min_val) / bucket_range), bucket_count - 1)
buckets[idx].append(x)
for b in buckets:
b.sort()
result = [x for b in buckets for x in b]
for i in range(len(arr)):
arr[i] = result[i]
return arr

C/C++: 需动态数组,实现略繁,思路同 Python。


基数排序 (Radix Sort)

原理

按位排序:把整数看成多位数(个位、十位、百位……),从最低位到最高位依次做稳定排序。每轮只按当前位排序,必须用稳定排序(如计数排序),才能保证之前轮的相对顺序不被破坏。

为何从低位到高位? 因为高位决定数的大小,低位只起“微调”作用。先按低位排好,再按高位排时,同一高位内的数已经按低位有序,整体自然有序。

取某一位的方法:$(x \div 10^{k-1}) \bmod 10$。例如 $exp=1$ 取个位,$exp=10$ 取十位。

逐步示例

基数排序示例(两位数)

数组 $[52, 21, 18, 91, 93, 35]$,最大 2 位,需 2 轮(个位、十位):

第 1 轮(个位,exp=1):按个位数字排序

  • 个位:2, 1, 8, 1, 3, 5
  • 计数排序后(稳定):$[21, 91, 52, 93, 35, 18]$(个位 1→1→2→3→5→8)

第 2 轮(十位,exp=10):按十位数字排序

  • 十位:2, 9, 5, 9, 3, 1
  • 计数排序后(稳定):$[18, 21, 35, 52, 91, 93]$(十位 1→2→3→5→9→9)

完成。注意十位同为 9 的 91、93 保持上一轮顺序,靠稳定性保证。

单位数示例(原数组 $[5, 2, 8, 1, 9, 3]$)

可视作 05, 02, 08, 01, 09, 03,只需 1 轮(个位):

  • 个位计数排序 → $[1, 2, 3, 5, 8, 9]$

复杂度

  • 时间:$O(n \cdot k)$,$k$ 为最大位数
  • 空间:$O(n + k)$

代码实现

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def counting_sort_by_digit(arr, exp):
n = len(arr)
output = [0] * n
count = [0] * 10
for i in range(n):
digit = (arr[i] // exp) % 10
count[digit] += 1
for i in range(1, 10):
count[i] += count[i - 1]
for i in range(n - 1, -1, -1):
digit = (arr[i] // exp) % 10
output[count[digit] - 1] = arr[i]
count[digit] -= 1
for i in range(n):
arr[i] = output[i]

def radix_sort(arr):
if not arr:
return arr
max_val = max(arr)
exp = 1
while max_val // exp > 0:
counting_sort_by_digit(arr, exp)
exp *= 10
return arr

C/C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void counting_sort_by_digit(int arr[], int n, int exp) {
int output[n];
int count[10] = {0};
for (int i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10;
output[count[digit] - 1] = arr[i];
count[digit]--;
}
for (int i = 0; i < n; i++)
arr[i] = output[i];
}

void radix_sort(int arr[], int n) {
int max_val = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > max_val) max_val = arr[i];
for (int exp = 1; max_val / exp > 0; exp *= 10)
counting_sort_by_digit(arr, n, exp);
}