C语言qsort函数实战指南:参数解析、回调实现与模拟

Aria
Aria
发布时间:2026-10-16 | 4人浏览过
原创

本文深入解析C语言标准库中的快速排序函数 qsort。涵盖其核心参数含义、回调函数的编写技巧,以及如何处理整型数组和复杂结构体的排序需求。文章还包含 qsort 的底层冒泡模拟实现,帮助理解指针运算在泛型排序中的应用。

回调函数机制

qsort 是 C 语言标准库中的一个通用排序函数,其核心依赖于回调函数。回调函数是一个通过函数指针被调用的函数。当函数的指针作为参数传递给另一个函数时,接收方利用该指针调用其所指向的函数,即构成回调。这种机制使得排序算法不需要知道具体数据的类型,只需通过回调函数返回的比较结果来指导排序逻辑。

qsort 函数原型解析

在使用 qsort 前,需明确其四个关键参数:
void* base:待排序数组的首元素地址。
size_t num:数组中元素的总个数。
size_t width:单个元素的大小(字节数),通常使用 sizeof(arr[0]) 获取。
int (*cmp)(const void*, const void*):比较函数的地址。该函数接收两个元素指针,并返回整数以指示顺序。

比较函数的返回值规则严格遵循以下标准:
1. 若返回值小于 0,表示第一个元素排在第二个元素之前(e1 < e2);
2. 若返回值等于 0,表示两元素相等;
3. 若返回值大于 0,表示第一个元素排在第二个元素之后(e1 > e2)。

整型数组排序示例

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

// 自定义比较函数:升序排列
int int_cmp(const void* e1, const void* e2)
{
    return *(int*)e1 - *(int*)e2;
}

int main()
{
    int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    // 调用 qsort
    qsort(arr, sz, sizeof(arr[0]), int_cmp);
    
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]); // 输出: 0 1 2 3 4 5 6 7 8 9
    }
    return 0;
}

由于 e1 和 e2 是无类型指针,直接解引用会导致编译错误。因此,必须在比较函数中将指针强制转换为具体类型(如 int*)后再进行解引用。此例展示了标准的回调流程:用户在主程序定义 int_cmp,而 qsort 内部负责调用它。

结构体数据排序

按结构体成员排序:字符串比较

以下代码演示对包含姓名和年龄的结构体数组,按姓名字典序排序。需注意 strcmp 的返回值特性:

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

struct Stu
{
    char name[20];
    int age;
};

// 按姓名升序排序
int str_name_cmp(const void* e1, const void* e2)
{
    // 强转为结构体指针后访问name字段
    return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

int main()
{
    struct Stu s[] = { {"zhangsan",18},{"lisi",17},{"wangwu",22} };
    int sz = sizeof(s) / sizeof(s[0]);
    
    qsort(s, sz, sizeof(s[0]), str_name_cmp);
    
    for (int i = 0; i < sz; i++)
    {
        printf("%s ", s[i].name); // 输出: lisi wangwu zhangsan
    }
    return 0;
}

按结构体成员排序:整型比较

// 续接上方结构体定义
int str_age_cmp(const void* e1, const void* e2)
{
    return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

// main函数中调用
// qsort(s, sz, sizeof(s[0]), str_age_cmp);

对于结构体内部的整型成员,处理方式与原生整型数组类似,关键在于先进行结构体类型的强制转换,再通过箭头操作符 > 访问目标字段。

qsort 模拟实现(冒泡排序版)

为了深入理解 qsort 的泛型特性,下面提供一个基于冒泡排序的模拟实现。重点在于处理无类型指针的字节级交换。

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

void Swap(char* p1, char* p2, size_t width)
{
    for (size_t i = 0; i < width; i++)
    {
        char tmp = *p1;
        *p1 = *p2;
        *p2 = tmp;
        p1++;
        p2++;
    }
}

void qsort_bubble(void* base, size_t sz, size_t width, int(*compare)(const void* e1, const void* e2))
{
    for (size_t i = 0; i < sz - 1; i++)
    {
        int change = 0;
        for (size_t j = 1; j < sz - i; j++)
        {
            // 计算当前相邻两个元素的地址
            // 将base视为char*以便进行字节偏移运算
            if (compare((char*)base + (j - 1) * width, (char*)base + j * width) > 0)
            {
                Swap((char*)base + (j - 1) * width, (char*)base + j * width, width);
                change = 1;
            }
        }
        if (change == 0)
            break; // 优化:若无交换则提前结束
    }
}

int main()
{
    int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    // 使用模拟实现的冒泡排序
    qsort_bubble(arr, sz, sizeof(arr[0]), int_cmp);
    
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

在上述模拟实现中,Swap 函数接受字节指针 char*,通过循环逐个字节交换数据,从而实现了不依赖具体数据类型的通用交换逻辑。这也是库函数能够处理 struct、float 等各种类型的核心技术。

升降序控制逻辑

回顾 compare 函数:当返回正值(前 > 后)时触发交换,最终小的元素会沉到前面,形成升序。若要实现降序,只需在比较函数中反转判断逻辑(如返回 *val2 - *val1),使得大的元素交换至前方。

实际场景应用:LeetCode 977

在处理包含负数的数组平方排序问题时,qsort 是一种简洁的解决方案。先将所有元素平方,再统一排序:

#include <math.h>

int compare(const void* elem1, const void* elem2)
{
    return *(int*)elem1 - *(int*)elem2;
}

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    *returnSize = numsSize;
    for(int i=0; i<numsSize; i++)
    {
        nums[i] = pow(nums[i], 2);
    }
    qsort(nums, numsSize, sizeof(nums[0]), compare);
    return nums;
}

尽管 qsort 使用便捷,但在算法竞赛或特定性能敏感场景中,应根据数据特征选择更高效的排序策略(如双指针法)。以上内容涵盖了从基础用法到底层原理的完整知识链。

以上就是关于C语言库函数qsort的使用详解,更多关于C/C++排序算法的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表