前言
我们知道,qsort的底层排序代码原理是快排,但我们今天利用更简单的冒泡排序实现qsort函数
一、冒泡函数的原理
以上参考我曾经写的一篇博客
链接:https://blog.csdn.net/Tlzns/article/details/128406959?spm=1001.2014.3001.5501
二、qsort函数分析
我们要用冒泡模拟一个qsort函数,在我们已经熟悉冒泡的情况下,分析qsort的参数,进行模拟
qsort有四个形参,分别是待排数组的首地址,数组元素个数,以及数组单个元素的字节大小,还有一个比较函数
由于我们得到的是void*类型的指针,该指针不能通过解引用,所以如何传参比较函数中元素的大小,以及如何将函数中的元素进行交换是我们需要解决的问题
三、实现过程
下面是冒泡排序基本框架
void Bubble_qsort(void* base, size_t num, size_t width, int (*cmp)(const void* p1, const void* p2))
{
int i = 0;
for (i = 0; i < num - 1, i++)
{
int flag = 1;
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (cmp > 0)//调用比较函数获得的返回值来判断是否普交换值
{
swap();
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
关于冒泡详情可以查看我之前写的关于冒泡的一篇文章
链接:https://blog.csdn.net/Tlzns/article/details/128406959
我们不难看出,有待我们解决的问题有:
1.在viod类型指针的前提下如何给比较函数cmp传参获得正确的返回值
2.在viod类型指针的前提下如何交换需要交换的两个值
进一步观察qsort获得的形参,有待排数据元素个数num,单个元素字节宽度width
作为qsort函数的作者,并不知道未来使用者用来排序什么类型
但我们可以默认获得的数据类型为char,获得该元素每个数据的起始地址
我们在调用cmp函数时可以进行以下操作
cmp((char*)base + j * width, (char*)base + (j + 1) * width)
我们以int类型的数组为例
我们将图中的数据首地址传给比较函数,通过函数使用者获得对应的返回值 判断是否需要交换
我们解决了如何调用cmp函数,接下来需要解决如何交换对应的元素
我们知道char类型的数据char类型的数据在内存中占一个字节,short类型占两个字节,int 占四个字节
而现在我们不能通过解引用的方式创建临时变量直接交换对应的值,我们可以将元素数据中的每个字节都进行交换
从而最终交换了两个元素
swap(char* p1, char* p2,int width)
{
while (width)
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
width--;
}
}
实现代码
swap(char* p1, char* p2,int width)
{
while (width)
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
width--;
}
}
void Bubble_qsort(void* base, size_t num, size_t width,int (*cmp)(const void *p1,const void *p2))
{
size_t i = 0;
for (i = 0; i < num-1; i++)
{
int j = 0;
int flag = 1;
for (j = 0; j < num - 1 - i; j++)
{
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width))
{
swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
以上就是qsort函数用冒泡算法的模拟实现