在C语言里,数组排序指的是将一段连续存储的同类型数据按照从小到大或从大到小的规则重新排列。由于C语言不提供内置的排序函数供初学者直接使用(标准库的qsort需要理解函数指针),手写排序算法既是练习数组操作和循环控制的好机会,也能让人看清不同算法在交换次数和比较次数上的真实差距。理解这些基础算法,对后续学习结构体和文件数据整理都有直接帮助。

冒泡排序的实现与细节分析
冒泡排序的核心思想是:从数组第一个元素开始,依次比较相邻的两个元素,如果前面的数比后面的大就交换位置。这样一轮下来,最大的数就会像气泡一样“浮”到数组末尾。接着对前面的元素重复同样的过程,直到所有元素都有序。这种写法最容易被理解,因此常常作为教学示例出现。
在代码层面,我们需要两层循环。外层循环控制已经排好多少个大数,内层循环负责在尚未排好的区间内做相邻比较。一个常见的优化是,如果某一轮内没有发生任何交换,说明数组已经有序,可以提前结束。下面给出带提前退出优化的冒泡排序代码:
#include <stdio.h>
void bubble_sort(int arr[], int n) {
int i, j, temp;
int swapped;
for (i = 0; i < n - 1; i++) {
swapped = 0;
for (j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = 1;
}
}
if (swapped == 0) {
break;
}
}
}
int main() {
int data[] = {5, 2, 9, 1, 3};
int size = sizeof(data) / sizeof(data[0]);
bubble_sort(data, size);
for (int k = 0; k < size; k++) {
printf("%d ", data[k]);
}
return 0;
}
冒泡排序的时间复杂度在最坏和平均情况下都是 O(n^2),当数据量超过几千时就会明显变慢。它的优点是稳定(相等元素不改变原有相对顺序),并且代码非常短,调试方便。缺点也很突出:不必要的交换和比较太多。如果在面试或作业中只要求“能排就行”,冒泡可以胜任;但在真实项目里处理大规模数据一般不会选它。
选择排序与快速排序的对比实践
选择排序的思路和冒泡不同:它每一轮都在未排序区间中找到最小(或最大)的元素,然后直接和区间第一个位置交换。这样做把“频繁交换”变成了“每轮最多一次交换”,虽然比较次数还是 O(n^2),但数据移动次数降低了。下面的代码演示了升序选择排序:
#include <stdio.h>
void select_sort(int arr[], int n) {
int i, j, min_idx, temp;
for (i = 0; i < n - 1; i++) {
min_idx = i;
for (j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx]) {
min_idx = j;
}
}
if (min_idx != i) {
temp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = temp;
}
}
}
int main() {
int data[] = {4, 6, 2, 8, 1};
int size = sizeof(data) / sizeof(data[0]);
select_sort(data, size);
for (int k = 0; k < size; k++) {
printf("%d ", data[k]);
}
return 0;
}
快速排序则是另一套逻辑:选一个基准值,把比它小的放左边、比它大的放右边,再对左右两部分递归处理。它的平均时间复杂度是 O(n log n),适合大数据量。下面给出一个简单的递归快排示例:
#include <stdio.h>
void quick_sort(int arr[], int left, int right) {
if (left >= right) return;
int pivot = arr[left];
int i = left, j = right;
int temp;
while (i < j) {
while (i < j && arr[j] >= pivot) j--;
while (i < j && arr[i] <= pivot) i++;
if (i < j) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[left] = arr[i];
arr[i] = pivot;
quick_sort(arr, left, i - 1);
quick_sort(arr, i + 1, right);
}
int main() {
int data[] = {7, 3, 9, 2, 5};
int size = sizeof(data) / sizeof(data[0]);
quick_sort(data, 0, size - 1);
for (int k = 0; k < size; k++) {
printf("%d ", data[k]);
}
return 0;
}
从实践角度看,选择排序代码比快排好写,也不易出递归栈溢出问题,但效率依旧不高。快排写错边界条件就容易死循环或越界,比如上面代码中left >= right的退出判断就不能少。若数组已经接近有序,快排可能退化成 O(n^2),这时可随机选基准来缓解。对于普通学习者,先写对冒泡和选择,再挑战快排是比较稳的路线。
用标准库qsort处理数组排序
除了自己写算法,C语言标准库提供了qsort函数,声明在stdlib.h里。它基于快速排序的变体实现,通过函数指针让用户自定义比较规则,因此可以排序任意类型的数组,包括结构体数组。掌握qsort能省掉大量重复代码,也是理解回调函数的入门练习。
使用qsort时必须写一个比较函数,其原型为int cmp(const void *a, const void *b)。函数返回负值表示 a 应排在 b 前,返回零表示相等,返回正值表示 a 应排在 b 后。对整型数组来说,先把指针转成int *再相减即可。示例代码如下:
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int main() {
int data[] = {10, 3, 8, 1, 6};
int size = sizeof(data) / sizeof(data[0]);
qsort(data, size, sizeof(int), cmp);
for (int k = 0; k < size; k++) {
printf("%d ", data[k]);
}
return 0;
}
使用qsort时要注意第三个参数sizeof(int)写错会导致内存读取错位,比较函数里若直接返回相减结果在数值极大时可能有溢出风险,更稳妥的写法是使用大于小于判断返回 1、0、-1。另外,qsort不保证相等元素的原有顺序,因此不属于稳定排序。当项目里需要排基础类型数组时,优先用qsort减少bug;当面试要求手撕算法时,再使用前面写的冒泡、选择或快排来展示逻辑。
C语言数组排序bubble_sort修改时间:2026-08-19 03:18:32