冒泡排序模拟qsort函数

简介: 冒泡排序模拟qsort函数

前言:

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

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


1. qsort 函数介绍

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

7777db36ef84e337fd79ea596c56e8b8_702009fe81d04775bf7b058ae1a7b142.png

可以解读出:

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

qsort 函数不返回数据;

使用 qsort 需要传递四个参数

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

475e4bdd5c439512c19b3d4220bb2095_695698f927e44a57821a495e097e751c.png

先来看看前三个:

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

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

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

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

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

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

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

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

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

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

看最后一个:

7718d3cca280bf77ef3b56e8e2bb0d7d_31f464f0cf25447fb8870dc04bbe9459.png这里就直接解释吧:

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

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

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

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

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

142b8ec5046f707579de734823e0dce2_cd36652ab15c457bb5487a1c4bc8bbe4.png

是的,比较两个元素就是这个函数的作用,这两个元素可以是相邻两个元素(注意: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 函数就是执行 交换相邻元素 任务的

563aff8366c6d8257224cf8984c7ff70_9cee42c4a4744faab40a946a5ad3b46f.png

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

理应,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;
}

总结:

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

目录
相关文章
|
6月前
|
搜索推荐 C语言
模拟实现qsort函数:冒泡排序详解
模拟实现qsort函数:冒泡排序详解
39 1
|
7月前
冒泡排序的快速排序——qsort函数的模拟实现
冒泡排序的快速排序——qsort函数的模拟实现
42 1
|
7月前
|
算法 C语言
用冒泡排序模拟C语言中的内置快排函数qsort!
用冒泡排序模拟C语言中的内置快排函数qsort!
|
C语言
c语言用冒泡排序模拟实现qsort排序
c语言用冒泡排序模拟实现qsort排序
78 0
qsort函数和模拟实现qsort函数
qsort函数和模拟实现qsort函数
|
7月前
|
搜索推荐 C语言
冒泡排序模拟实现qsort()函数
冒泡排序模拟实现qsort()函数
45 0
|
程序员
qsort函数的模拟实现
qsort函数的模拟实现
57 1
qsort函数详细讲解以及利用冒泡排序模拟实现qsort函数
qsort函数详细讲解以及利用冒泡排序模拟实现qsort函数
73 0
|
算法 C语言
冒泡排序 - 【利用冒泡排序模拟实现快速排序的功能】
冒泡排序 - 【利用冒泡排序模拟实现快速排序的功能】
下一篇
DataWorks