C语言学习记录--深入理解指针(5)(qsort的练习)

     这一篇就是关于指针的最后一战了,主要是练习一个叫做  qsort   的C语言库函数

正文开始:

一.什么是qsort函数?

     qsort  就是 quick sort,也就是“快速排序”,意思就是说qsort就是一个排序函数,和之前写的冒泡排序不同,冒泡排序只能排序整型数据,而qsort可以排序任意类型的数据。

注意:使用qosrt需要包含头文件  #include<stdlib.h>

下面是我在cpulspuls 网站截到的图片,用来作qsort的说明:

 可以看到,这个函数的使用需要传递4个参数,分别是:

1.要排序的数组的首元素指针(即数组名)。

2.待排序数组中的元素个数。(可以用  sizeof(arr)/sizeof(arr[0])  )

3.待排序数组中每个元素的字节大小(即 sizeof(arr[0]  )

4.比较两个元素大小比较的函数的指针(即函数名)

   前面三个参数都很好理解,关键在于第四个,这是一个比较数组中元素大小的函数,根据这个函数的返回值决定元素的相对顺序。

二.qsort的应用

代码格式如下:

#include<stdlib.h>
void compare(const void* p1, const void* p2)
{

}
int main()
{
    int arr[10] = { 9,0,5,7,3,2,4,1,8,6 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), compare);
    return 0;
}

然后来写函数:

void compare(const void* p1, const void* p2)
{
    if (*(int*)p1 > *(int*)p2)//因为void*类型不能解引用,所以这里使用(int*)来强制类型转换。
    {
        return 1;
    }
    else if (*(int*)p1 < *(int*)p2)
    {
        return -1;   
    }
    else
    {
        return 0;
    }
}

返回大于0的数(1)和小于0的数(-1)来比较元素大小,

完整代码效果如下:

#include<stdlib.h>
void compare(const void* p1, const void* p2)
{
    if (*(int*)p1 > *(int*)p2)
    {
        return 1;
    }
    else if (*(int*)p1 < *(int*)p2)
    {
        return -1;   
    }
    else
    {
        return 0;
    }
}

void print(int* arr, int sz)
{
    int i = 0;
    for (i = 0;i < sz;i++)
    {
        printf("%d ", *(arr + i));
    }
    printf("\n");
}

int main()
{
    int arr[10] = { 9,0,5,7,3,2,4,1,8,6 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    printf("排序前:");
    print(arr, sz);
    qsort(arr, sz, sizeof(arr[0]), compare);
    printf("排序后:");
    print(arr, sz);
    return 0;
}

三.qosrt的其他应用举例

1. 字符串排序(按字典序)​

在处理文本数据时,我们经常需要对字符串进行排序,比如将单词按字典序排列。以下是使用qsort函数实现字符串排序的代码:

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

// 字符串比较函数(用于qsort)
int compare_strings(const void *a, const void *b) {
    // 将void指针转换为char**,再解引用得到char*
    return strcmp(*(const char **)a, *(const char **)b);
}

int main() {
    const char *strings[] = {
        "banana", "apple", "cherry", "date", "elderberry"
    };
    int n = sizeof(strings) / sizeof(strings[0]);

    // 排序字符串数组
    qsort(strings, n, sizeof(const char *), compare_strings);

    // 输出排序结果
    printf("排序后的字符串:\n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", strings[i]);
    }

    return 0;
}

运行结果:

2. 结构体排序(按学生成绩降序)​

当需要对自定义结构体数据进行排序时,qsort同样能发挥作用。假设我们有一个学生结构体,包含姓名和成绩信息,现在要按成绩从高到低对学生进行排序,代码如下:​

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

// 定义学生结构体
typedef struct {
    char name[50];
    int score;
} Student;

// 学生比较函数(按成绩降序)
int compare_students(const void *a, const void *b) {
    // 将void指针转换为Student*
    const Student *student_a = (const Student *)a;
    const Student *student_b = (const Student *)b;
    // 降序排序:b - a
    return student_b->score - student_a->score;
}

int main() {
    Student students[] = {
        {"Alice", 85},
        {"Bob", 92},
        {"Charlie", 78},
        {"David", 92},
        {"Eve", 88}
    };
    int n = sizeof(students) / sizeof(students[0]);

    // 排序学生数组
    qsort(students, n, sizeof(Student), compare_students);

    // 输出排序结果
    printf("按成绩降序排列的学生:\n");
    for (int i = 0; i < n; i++) {
        printf("%s: %d分\n", students[i].name, students[i].score);
    }

    return 0;
}

运行结果:

四.使用冒泡排序的底层逻辑模拟qsort

  当我们学会了冒泡排序后,发现它只能排序整型数据,那么有办法让冒泡排序算法(Bubble_sort)也能够排序任意类型的数据吗?

有的兄弟,有的

接下来就是本篇的重点了,即使用冒泡排序的底层逻辑模拟qsort。

  我这里直接先把代码端上来吧:

#include<stdio.h>
void swap(char* bf1, char* bf2, size_t width)
{
    int i = 0;
    char tmp = 0;
    for (i = 0;i < width;i++)
    {
        tmp = *bf1;
        *bf1 = *bf2;
        *bf2 = tmp;

        bf1++;
        bf2++;
    }
}

int cmp(const void* p1, const void* p2)
{
    return *(int*)p1 - *(int*)p2;
}

void print(int arr[10], int sz)
{
    int i = 0;
    for (i = 0;i < sz;i++)
    {
        printf("%d ", *(arr + i));
    }
    printf("\n");
}

void bubble_sort(void* base, size_t sz, size_t width, int(*cmp)(const void* p1, const void* p2))
{
    int i = 0;
    for (i = 0;i < sz - 1;i++)
    {
        int j = 0;
        for (j = 0;j < sz - 1 - i;j++)
        {
            //这个函数比较元素大小
            if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
            {
                //这个函数用来交换元素位置(交换了元素的地址)
                swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
            }
        }
    }
}

int main()
{
    int arr[10] = { 10,9,8,7,6,5,4,3,2,1 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz, sizeof(arr[0]), cmp);
    print(arr, sz);
    return 0;
}

这段代码实现了一个通用的冒泡排序算法,它能够对任意类型的数据进行排序,具体功能包括:

  1. 内存交换函数swap函数用于交换两个内存块的内容
  2. 比较函数cmp函数用于定义元素之间的比较规则
  3. 打印函数print函数用于输出排序结果
  4. 通用冒泡排序bubble_sort函数实现核心排序逻辑
  5. 主函数:演示如何使用上述功能对整数数组进行排序

我想写更清楚一点儿的解释,可奈何有点力不从心(说白了现在还没有能力用文字把所有代码解释清楚)

主要难点在于这两个地方:

  1. 内存交换函数swap函数用于交换两个内存块的内容
  2. 比较函数cmp函数用于定义元素之间的比较规则

swap函数是实现元素交换的核心:

void swap(char* bf1, char* bf2, size_t width)
{
    int i = 0;
    char tmp = 0;
    for (i = 0; i < width; i++)
    {
        tmp = *bf1;
        *bf1 = *bf2;
        *bf2 = tmp;

        bf1++;
        bf2++;
    }
}

这个函数通过逐字节交换两个内存块的内容来实现元素交换。由于使用了char*指针,每次只能访问一个字节,因此需要循环width次,确保交换整个元素的内容。

比较函数cmp是定义排序规则的关键:

int cmp(const void* p1, const void* p2)
{
    return *(int*)p1 - *(int*)p2;
}

比较函数的设计遵循以下原则:

  • 接受两个const void*类型的参数
  • 将参数转换为实际数据类型的指针
  • 根据比较结果返回负值、零或正值

其他的点在熟悉C语言指针的情况下是很容易理解的。

OK!指针的内容我也终于学完了,真是一场盛大得知识盛宴啊。

学习过程终归有些枯燥和乏味,但想起来最终目标还很远,所以还是要砥砺前行,感觉把自己说的有点高大上了,算了……一步步来。

指针到此结束,感谢各位的阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值