C语言DataSort如何实现高效排序?

99ANYc3cd6
预计阅读时长 30 分钟
位置: 首页 C语言 正文

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

c语言datasort
(图片来源网络,侵删)

下面我将从以下几个方面为你详细讲解:

  1. 核心概念:排序的通用思路。
  2. 常用排序算法:介绍几种最经典和常用的排序算法,并提供 C 语言代码示例。
  3. C 标准库中的排序函数:介绍如何直接使用 C 标准库提供的强大排序工具。
  4. 如何选择排序算法:不同算法的优缺点和适用场景。
  5. 一个完整的示例程序:将所有内容整合在一起。

核心概念

无论使用哪种排序算法,基本步骤都类似:

  1. 比较:比较两个或多个元素的大小。
  2. 交换:如果它们的顺序不符合要求,就交换它们的位置。
  3. 重复:对数据集中的所有元素重复以上过程,直到整个序列有序。

为了方便演示,我们通常使用整数数组,但这些算法同样适用于任何可以比较的数据类型(如浮点数、字符串、结构体等)。


常用排序算法及 C 语言实现

我们将实现以下几种算法:

c语言datasort
(图片来源网络,侵删)
  • 冒泡排序
  • 选择排序
  • 插入排序
  • 快速排序

准备工作:交换函数和打印函数

在开始之前,我们先定义两个辅助函数,它们在所有排序算法中都会用到。

#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. 选择排序

思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。

c语言datasort
(图片来源网络,侵删)

特点:每次遍历只记录最小/大元素的索引,只进行一次交换,交换次数比冒泡排序少,但时间复杂度仍然是 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 语言中的数据排序!

-- 展开阅读全文 --
头像
c语言libevent
« 上一篇 04-19
C语言如何实现Hessian二进制序列化?
下一篇 » 04-19

相关文章

取消
微信二维码
支付宝二维码

目录[+]