C语言qsort函数应用

一、qsort 函数的基本介绍

qsort 是 C 标准库中的一个快速排序函数,位于 <stdlib.h> 头文件中。它的原型如下:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
  • base:指向待排序数组的首元素指针。
  • nmemb:数组中元素的数量。
  • size:每个元素的大小(以字节为单位)。
  • compar:比较函数的指针,用于决定排序顺序。

二、比较函数的编写

比较函数 compar 的返回值决定了排序顺序:

  • 返回负数:第一个参数应排在第二个参数之前。
  • 返回零:两参数相等。
  • 返回正数:第一个参数应排在第二个参数之后。

比较函数示例(升序排序整型数组):

int compare_ints(const void *a, const void *b) {
    int x = *(const int *)a;
    int y = *(const int *)b;
    return (x > y) - (x < y);
}

三、降序排序的实现

只需在比较函数中反转返回值:

int compare_ints_desc(const void *a, const void *b) {
    return (*(int *)b - *(int *)a);
}

四、性能与稳定性

qsort 平均时间复杂度为 O(n log n),但不保证稳定性(相等元素的相对顺序可能改变)。如需稳定排序,需使用其他算法。

五、常见数据类型的排序示例

1、整型数组排序
#include <stdio.h>
#include <stdlib.h>

int compare_ints(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

int main() {
    int arr[] = {5, 2, 8, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(int), compare_ints);

    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);

    return 0;
}
1.1、其他排序规则

需要实现一个整型数组的排序,排序规则为:对于任意两个数字 ab,比较 ab(正向拼接)和 ba(反向拼接)的值,若 ab < ba,则 a 应排在 b 前面。 最后整个数组可拼接成最大值。

  1. 自定义比较函数:利用 qsort 函数的自定义比较功能,定义拼接后的字符串比较逻辑。
  2. 拼接字符串处理:将两个整数转换为字符串并拼接,比较拼接后的字符串大小。
  3. 避免数值溢出:直接拼接字符串而非转换为数值,避免大数溢出问题。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 自定义比较函数
int compare(const void *a, const void *b) {
    char str_ab[24], str_ba[24]; // 假设数字不超过12位(避免溢出)

    // 将a和b转换为字符串
    sprintf(str_ab, "%d%d", *(int *)a, *(int *)b);
    sprintf(str_ba, "%d%d", *(int *)b, *(int *)a);

    // 比较拼接后的字符串
    return strcmp(str_ab, str_ba);
}

// 示例调用
int main() {
    int arr[] = {3, 30, 34, 5, 9};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(int), compare);

    // 输出排序结果
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
  1. 比较函数 compare

    • 将两个整数 ab 分别拼接为 abba 的字符串形式。
    • 使用 strcmp 比较两个字符串的字典序,返回结果作为排序依据。
  2. 主函数

    • 定义测试数组 arr,调用 qsort 进行排序。
    • 排序后的数组按规则输出,例如输入 {3, 30, 34, 5, 9},输出为 3 30 34 5 9(因为 330 < 303334 < 343 等)。
注意事项
  • 字符串缓冲区大小:假设每个数字不超过12位,拼接后的字符串长度不超过24位。若数字更大,需调整缓冲区大小。
  • 性能优化:频繁的字符串拼接可能影响性能,若数据量较大,可考虑优化拼接方式或缓存结果。
2、字符串数组排序
2.1、使用指针数组定义字符串数组

指针数组方式适合存储固定数量的字符串,每个元素是指向字符串的指针。
示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare(const void *a, const void *b) {
    return strcmp(*(const char **)a, *(const char **)b);
}

int main() {
    const char *arr[] = {"banana", "apple", "cherry"};
    int n = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, n, sizeof(const char *), compare);
    for (int i = 0; i < n; i++) printf("%s\n", arr[i]);
    return 0;
}
  • 关键点:比较函数需解引用两层指针(*(const char **)),因为 qsort 传递的是数组元素的地址(即 char ** 类型)。

2.2、使用二维字符数组定义

二维数组方式适合存储长度固定的字符串,内存连续但可能浪费空间。
示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare(const void *a, const void *b) {
    return strcmp((const char *)a, (const char *)b);
}

int main() {
    char arr[][10] = {"banana", "apple", "cherry"};
    int n = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, n, sizeof(arr[0]), compare);
    for (int i = 0; i < n; i++) printf("%s\n", arr[i]);
    return 0;
}
  • 关键点:比较函数直接强转为 const char *,因为二维数组的每个元素是字符数组(char[10]),传递给 qsort 的是其首地址。

2.3、动态字符串数组(指针 + 动态内存)

动态分配方式灵活,适合运行时确定字符串数量和内容。
示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare(const void *a, const void *b) {
    return strcmp(*(const char **)a, *(const char **)b);
}

int main() {
    char **arr = malloc(3 * sizeof(char *));
    arr[0] = strdup("banana");  // 动态分配并复制字符串
    arr[1] = strdup("apple");
    arr[2] = strdup("cherry");
    int n = 3;
    qsort(arr, n, sizeof(char *), compare);
    for (int i = 0; i < n; i++) {
        printf("%s\n", arr[i]);
        free(arr[i]);  // 释放每个字符串
    }
    free(arr);  // 释放指针数组
    return 0;
}
  • 关键点:动态分配需管理内存(malloc/free),比较函数与指针数组方式一致。使用 strdup 简化字符串复制(需手动释放)。

总结
  • 指针数组:适合静态字符串集合,比较函数需解引用两层指针。
  • 二维数组:适合固定长度字符串,内存连续但不够灵活。
  • 动态分配:灵活性强,需注意内存管理。

根据实际需求选择合适的方式,注意比较函数和内存管理的差异。

3、结构体排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[50];
    int age;
} Person;

int compare_persons_by_age(const void *a, const void *b) {
    return ((Person *)a)->age - ((Person *)b)->age;
}

int main() {
    Person people[] = {{"Alice", 25}, {"Bob", 20}, {"Charlie", 30}};
    int n = sizeof(people) / sizeof(people[0]);

    qsort(people, n, sizeof(Person), compare_persons_by_age);

    for (int i = 0; i < n; i++)
        printf("%s: %d\n", people[i].name, people[i].age);

    return 0;
}
4、浮点数排序-注意事项

由于浮点数精度问题,直接相减可能导致错误。建议使用以下方式:

int compare_floats(const void *a, const void *b) {
    float x = *(const float *)a;
    float y = *(const float *)b;
    return (x > y) - (x < y);
}
5、二维数组排序

以下使用 C 语言的 qsort 函数对二维数组进行多种排序方式的实现。假设二维数组为 int arr[M][N],其中 M 为行数,N 为列数。

5.1、按某列排序(全体行参与排序)
int compare_col(const void *a, const void *b, int col) {
    int *row1 = (int *)a;
    int *row2 = (int *)b;
    return (row1[col] > row2[col]) - (row1[col] < row2[col]);
}

// 按第 k 列升序排序
qsort(arr, M, sizeof(arr[0]), 
      (int (*)(const void *, const void *))compare_col);
5.2、按某行排序(全体列参与排序)
int compare_row(const void *a, const void *b, int row) {
    int *col1 = (int *)a;
    int *col2 = (int *)b;
    return (arr[row][*col1] > arr[row][*col2]) - 
           (arr[row][*col1] < arr[row][*col2]);
}

// 按第 k 行升序排序(需额外处理)
int indices[N];
for (int i = 0; i < N; i++) indices[i] = i;
qsort(indices, N, sizeof(int), 
      (int (*)(const void *, const void *))compare_row);

也可行列互换后排序,再行列互换。

5.3、仅对某列排序(其他列不参与)
// 需将目标列提取为单独数组
int target_col[M];
for (int i = 0; i < M; i++) target_col[i] = arr[i][k];
qsort(target_col, M, sizeof(int), compare_int);

// 再写回原数组
for (int i = 0; i < M; i++) arr[i][k] = target_col[i];
5.4、全体元素排序(展平为一维)
int compare_all(const void *a, const void *b) {
    return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}

qsort(&arr[0][0], M * N, sizeof(int), compare_all);
5.5、多条件排序(第一列升序,第二列降序)
int compare_multi(const void *a, const void *b) {
    int *row1 = (int *)a;
    int *row2 = (int *)b;
    if (row1[0] != row2[0]) 
        return (row1[0] > row2[0]) - (row1[0] < row2[0]);
    else
        return (row2[1] > row1[1]) - (row2[1] < row1[1]);
}

qsort(arr, M, sizeof(arr[0]), compare_multi);

注意事项
  • 对于按行排序和部分列排序,通常需要额外处理索引或数据提取
  • 多条件排序时,比较函数需正确处理主次条件
  • C 语言中二维数组的内存布局是连续的,可直接用 &arr[0][0] 访问全体元素

【免责声明:本文代码来自AI生成,可能有误,请自行判断,别骂我骂AI谢谢:-)】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值