"Data Sort" 在 C 语言中通常指的是排序算法的实现,排序是将一组数据按照特定的顺序(如升序、降序)重新排列的过程,这是计算机科学中非常基础且重要的操作。

下面我将从以下几个方面为你详细讲解:
- 核心概念:排序的通用思路。
- 常用排序算法:介绍几种最经典和常用的排序算法,并提供 C 语言代码示例。
- C 标准库中的排序函数:介绍如何直接使用 C 标准库提供的强大排序工具。
- 如何选择排序算法:不同算法的优缺点和适用场景。
- 一个完整的示例程序:将所有内容整合在一起。
核心概念
无论使用哪种排序算法,基本步骤都类似:
- 比较:比较两个或多个元素的大小。
- 交换:如果它们的顺序不符合要求,就交换它们的位置。
- 重复:对数据集中的所有元素重复以上过程,直到整个序列有序。
为了方便演示,我们通常使用整数数组,但这些算法同样适用于任何可以比较的数据类型(如浮点数、字符串、结构体等)。
常用排序算法及 C 语言实现
我们将实现以下几种算法:

- 冒泡排序
- 选择排序
- 插入排序
- 快速排序
准备工作:交换函数和打印函数
在开始之前,我们先定义两个辅助函数,它们在所有排序算法中都会用到。
#include <stdio.h>
// 交换两个整数的值
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 打印数组
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
a. 冒泡排序
思想:重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,遍历数列的工作是重复进行的,直到没有再需要交换的元素为止,这意味着该数列已经排序完成。
特点:简单易懂,但效率很低,时间复杂度为 O(n²),适合小规模数据或教学。
// 冒泡排序 (升序)
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// 每一轮遍历后,最大的元素会“冒泡”到数组末尾
// 所以内层循环可以减少一次
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 如果前一个元素大于后一个,则交换
swap(&arr[j], &arr[j + 1]);
}
}
}
}
b. 选择排序
思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。

特点:每次遍历只记录最小/大元素的索引,只进行一次交换,交换次数比冒泡排序少,但时间复杂度仍然是 O(n²)。
// 选择排序 (升序)
void selectionSort(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;
}
}
// 将找到的最小元素与未排序部分的第一个元素交换
swap(&arr[min_idx], &arr[i]);
}
}
c. 插入排序
思想:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
特点:对于小规模数据或基本有序的数据,效率非常高,时间复杂度平均为 O(n²),但在最好情况下(数组已有序)可以达到 O(n)。
// 插入排序 (升序)
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i]; // 当前要插入的元素
j = i - 1; // key 前一个元素的索引
// 将比 key 大的元素向后移动
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
// 将 key 插入到正确的位置
arr[j + 1] = key;
}
}
d. 快速排序
思想:采用分治法策略,选择一个基准元素,将数组分为两部分,左边部分都小于基准,右边部分都大于基准,然后对这两部分递归地执行同样的操作。
特点:平均时间复杂度为 O(n log n),是实践中非常常用的高效排序算法,但在最坏情况下(如数组已有序且每次都选到第一个或最后一个元素作为基准),会退化到 O(n²)。
// 快速排序的辅助函数:分区
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = (low - 1); // i 是小于基准的元素的边界索引
for (int j = low; j <= high - 1; 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) {
// pi 是分区索引,arr[pi] 现在在正确的位置
int pi = partition(arr, low, high);
// 分别对分区左右两边进行递归排序
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
C 标准库中的排序函数
在实际开发中,我们通常不需要自己从头实现排序算法,因为 C 标准库 <stdlib.h> 提供了非常高效的排序函数 qsort。
qsort 函数原型:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
参数说明:
base: 指向要排序的数组的第一个元素的指针。nmemb: 数组中元素的数量。size: 数组中每个元素的大小(以字节为单位)。compar: 指向比较函数的指针,这个函数决定了排序的顺序。
compar 比较函数:
这个函数需要由你自己实现,它接受两个指向要比较的元素的指针 (const void *),并返回一个整数:
- 返回负值:表示第一个元素小于第二个元素。
- 返回零:表示两个元素相等。
- 返回正值:表示第一个元素大于第二个元素。
使用 qsort 的示例:
// qsort 所需的比较函数 (用于升序排序整数)
int compareInts(const void* a, const void* b) {
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
}
int main_qsort_example() {
int data[] = { 9, 1, 8, 2, 7, 3, 6, 4, 5 };
int size = sizeof(data) / sizeof(data[0]);
printf("使用 qsort 排序前: ");
printArray(data, size);
qsort(data, size, sizeof(int), compareInts);
printf("使用 qsort 排序后: ");
printArray(data, size);
return 0;
}
qsort 的实现通常是高度优化的混合排序算法(如内省排序 Introsort),它结合了快速排序、堆排序和插入排序的优点,性能非常出色。
如何选择排序算法
| 算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 | 适用场景 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | 稳定 | 教学,数据量极小 |
| 选择排序 | O(n²) | O(n²) | O(1) | 不稳定 | 数据量小,交换成本高 |
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 | 数据量小,或基本有序 |
| 快速排序 | O(n log n) | O(n²) | O(log n) | 不稳定 | 通用,性能优异,是大多数情况下的首选 |
qsort |
O(n log n) | O(n log n) | O(log n) | 不稳定 | 实际开发首选,标准库实现,可靠高效 |
- 稳定性:如果相等的元素在排序后,它们的相对位置保持不变,则该排序算法是稳定的,这对于处理复杂数据(如按多个关键字排序)很重要。
- 选择建议:
- 学习和面试:务必掌握冒泡、选择、插入和快速排序的原理和代码实现。
- 实际项目开发:直接使用
qsort,它经过了充分测试和优化,性能可靠,能让你专注于业务逻辑而不是算法实现。
完整的示例程序
下面是一个将所有内容整合在一起的完整 C 程序,你可以直接编译和运行它。
#include <stdio.h>
#include <stdlib.h> // 为了使用 qsort
// ==================== 辅助函数 ====================
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// ==================== 排序算法实现 ====================
// 1. 冒泡排序
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j], &arr[j + 1]);
}
}
}
}
// 2. 选择排序
void selectionSort(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;
}
}
swap(&arr[min_idx], &arr[i]);
}
}
// 3. 插入排序
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
// 4. 快速排序
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high - 1; 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);
}
}
// 5. 标准库 qsort
int compareInts(const void* a, const void* b) {
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
}
// ==================== 主函数 ====================
int main() {
int data1[] = {64, 34, 25, 12, 22, 11, 90};
int data2[] = {64, 34, 25, 12, 22, 11, 90};
int data3[] = {64, 34, 25, 12, 22, 11, 90};
int data4[] = {64, 34, 25, 12, 22, 11, 90};
int data5[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(data1) / sizeof(data1[0]);
printf("原始数组: ");
printArray(data1, n);
printf("\n");
// 冒泡排序
bubbleSort(data1, n);
printf("冒泡排序后: ");
printArray(data1, n);
printf("\n");
// 选择排序
selectionSort(data2, n);
printf("选择排序后: ");
printArray(data2, n);
printf("\n");
// 插入排序
insertionSort(data3, n);
printf("插入排序后: ");
printArray(data3, n);
printf("\n");
// 快速排序
quickSort(data4, 0, n - 1);
printf("快速排序后: ");
printArray(data4, n);
printf("\n");
// 标准库 qsort
qsort(data5, n, sizeof(int), compareInts);
printf("qsort 排序后: ");
printArray(data5, n);
printf("\n");
return 0;
}
希望这份详细的指南能帮助你全面理解 C 语言中的数据排序!
