冒泡排序模拟qsort函数

欢迎来到 Claffic 的博客 💞💞💞

前言:

学习C语言,一般情况下都会接触到冒泡排序,你知道吗,用冒泡排序的思想可以模拟实现qsort函数(库函数的一种,可以实现快排)跟我来看看吧。

注:此博客包含进阶知识,建议学完C语言初阶知识再进行学习哦 ~  


1. qsort 函数介绍

打开你的 C/C++资源网站/软件,搜索 qsort 函数  cplusplus - qsort 

  可以解读出:

qsort 函数的功能是排序数组中的元素

qsort 函数不返回数据;

使用 qsort 需要传递四个参数

传递的四个参数大有讲头,这里详细解释:

先来看看前三个:

base: 直译是 “指向数组中要排序的第一个对象的指针,转换为 void* ”。

简单说就是 要排序,你得先把你要排序的数组给我 ,那为什么要转换为 void* 呢?

这里就不得不说 void* 的利弊 了:

好处:void* 可以接收任意指针类型,包容性极强;

缺陷:接收的指针不可直接使用,也就意味着使用前要进行类型转换

原因 就是 qsort 函数的作者不知道你要传递什么类型的数组,所以干脆就用覆盖范围最广的喽 ~

num: 直译是 “ 数组中由base指向的元素个数,size_t 是无符号整型 ” 。

这个比较好理解,就是数组中元素总和size_t 就是 unsigned int ,因为总和不可能为负数,类型是无符号整型也理所应当了。

size: 直译是 “ 数组中每个元素的字节大小 ” 。 

这个倒是好理解,但你知道它有什么用吗?嘿嘿,这里留个小悬念 ~

看最后一个:

这里就直接解释吧:

int (*compar)(const void*,const void*) 是函数指针,它叫做 compar

它指向的函数 需要两个参数(都是 void* 型,且指向不可变);

它指向的函数 返回整型数值。

那就是要给 qsort 传个函数呗,但传递的这个函数的作用是?

你想啊,假如我用冒泡排序的思想给一个整数数组排升序,是不是先要比较相邻两个元素的大小 在来决定是否进行交换

是的,比较两个元素就是这个函数的作用,这两个元素可以是相邻两个元素(注意:qsort 函数比较的不一定是两个相邻的元素,因为我们用冒泡排序的思想,所以可以理解为两个相邻的元素),指向它们的指针类型同样是 void* ,最广泛。

返回值呢?

简单来说,可以用两个元素做差来解释:

  a - b (a , b 都是整型)

a > b ,返回大于 0 的整数;

a = b ,返回 0 ;

a < b ,返回小于 0 的整数。

2.实现过程

充分认识了 qsort ,接下来就是用冒泡排序的思想来模拟它,

我们先来复习一遍冒泡排序:

//普通的冒泡排序:
void bub_sort(int* arr, int sz)
{
    for (int i = 0; i < sz - 1; i++)
    {
        for (int j = 0; j < sz - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int temp = 0;
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

在这个冒泡排序中,只能实现整型类型元素的排序;

我们的目标是实现多种类型元素的排序

所以要改善的部分是判断与交换的部分

我们先来写出框架:

void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void* e2))
{
    for (int i = 0; i < num - 1; i++)
    {
        for (int j = 0; j < num - 1 - i; j++)
        {
            if (cmp()>0)
            {
                //交换
                Swap();
            }
        }
    }

}

接下来就是实现 cmp 函数Swap 函数

2.1 cmp 函数部分

如果传参类型是 整型:
直接返回差值就好。

int int_cmp(const void* e1, const void* e2)
{
    return *(int*)e1 - *(int*)e2;
    //强制类型转换
}

如果传参类型是包含整型和字符串类型的 结构体:

先把结构体创建:

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

struct Stu s[3] = { {"zhangsan",20},{"lisi",60},{"wangwu",30} };

如果年龄排序结构体:

int age_cmp(const void* e1, const void* e2)
{
    return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
    //莫忘记强制类型转换  指向具体结构体成员
}

如果名字排序结构体:

实际上是字符串的比较,我们很容易想到 strcmp 函数,将比较的两个字符串传入函数即可。

int name_cmp(const void* e1, const void* e2)
{
    return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

 2.2 Swap 函数部分

Swap 函数就是执行 交换相邻元素 任务的

 既然两个数组的元素不能直接交换,那么我们就开辟一块小空间,通过这块小空间交换一个元素后再进行下一个元素的交换。

理应,Swap 函数需要指向数组第一个元素的指针,还有数组中每个元素的字节大小(揭开悬念)

代码:

void Swap(char* buf1, char* buf2, int size)
{
    for (int i = 0; i < size; i++)
    {
        char temp = *buf1;
        *buf1 = *buf2;
        *buf2 = temp;
        buf1++;
        buf2++;
    }
}

 到这里基本上就大功告成啦

2.3函数整体代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//交换函数
void Swap(char* buf1, char* buf2, int size)
{
    for (int i = 0; i < size; i++)
    {
        char temp = *buf1;
        *buf1 = *buf2;
        *buf2 = temp;
        buf1++;
        buf2++;
    }
}

//冒泡排序思想实现指定类型数组的排序
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void* e2))
{
    for (int i = 0; i < num - 1; i++)
    {
        for (int j = 0; j < num - 1 - i; j++)
        {
            if (cmp((char*)base+j*size,(char*)base+(j+1)*size)>0)
            {
                //交换
                Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }

}

//比较函数
int int_cmp(const void* e1, const void* e2)
{
    return *(int*)e1 - *(int*)e2;
}

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

int age_cmp(const void* e1, const void* e2)
{
    return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int name_cmp(const void* e1, const void* e2)
{
    return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//测试部分
void int_test()
{
    int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz, sizeof(arr[0]), int_cmp);

    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
}
void struct_test()
{
    struct Stu s[3] = { {"zhangsan",20},{"lisi",60},{"wangwu",30} };
    int sz = sizeof(s) / sizeof(s[0]);
    bubble_sort(s, sz, sizeof(s[0]), age_cmp);

}

int main()
{
    int_test();
    struct_test();
    return 0;
}

已上传至 我的gitee ,代码拿走不谢 ~


总结:

这篇博客带大家用冒泡排序的思想模拟了 qsort 函数,应用到了 函数回调 的知识点,属于指针进阶知识,你学会了吗?

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

关注我  不迷路!!! 

  • 31
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 31
    评论
C语言数组排序函数qsort是标准库函数,用于对数组进行排序。它的使用方法是通过传入一个比较函数来指定排序的规则。在给出的代码中,我们可以看到使用qsort函数对一个整型数组进行升序排序的例子。\[1\] 为了实现qsort函数的功能,我们可以使用一种较为简单的排序算法,比如冒泡排序算法来模拟实现一个具有排序数组、字符串、结构体等功能的bubble_sort函数。\[2\]这个函数的参数可以仿照qsort函数的参数,包括要排序的数组的起始地址、元素个数、每个元素的大小以及一个比较函数。\[3\] 具体实现bubble_sort函数函数体可以根据冒泡排序算法来编写,通过比较相邻的元素并交换位置来实现排序排序的规则可以通过比较函数来指定,根据需要可以实现升序或降序排序。 总结起来,qsort是C语言标准库中的数组排序函数,可以通过传入比较函数来指定排序规则。如果想要模拟实现类似功能的排序函数,可以使用一种简单的排序算法,比如冒泡排序,并根据需要实现相应的比较函数。 #### 引用[.reference_title] - *1* *2* *3* [【C语言】qsort()函数详解:能给万物排序的神奇函数](https://blog.csdn.net/weixin_72357342/article/details/130628874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Claffic

赏包辣条~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值