库函数《qsort》的模拟实现,原来如此简单

void my_sort(void* base,

size_t sz,

size_t width,

int (cmp)(void, void*));

有的小伙伴就会问函数指针是是什么?

就是用来接收函数的地址,用的指针,具体的原理,大家可以去优快云查,这里,我们就不多讲了。

局部代码:

void my_sort(void* base, size_t sz, size_t width, int (cmp)(void, void*))

{

//函数里面实则还是冒泡排序

int i = 0;

for (i = 0; i < sz; i++)

{

int j = 0;

for (j = 0; j < sz - 1 - i; j++)

{

//进行判断和交换

}

}

}

这就是qsort函数大致的框架,还有一点点小细节问题,处理了就完成了,加油哦。

三、局部函数实现

=================================================================

现在放在我们面前的问题,怎么进行数值的判断和交换。

int arr[10]={2,1,4,5,6,3};

我们以这个数组为例,我们想想,如果我们要排一个升序的数组,只需要我们传递给(cmp_int)函数的两个参数相减为正数,上一篇博客提到了口诀“左减右为升序,反之则降”,即就是e1 - e2 大于0 ,也就是e1>e2了。 注:函数参数(const void* e1,const void* e2)

知道了其中原理,就好实现了呗,if语句判断,如果(cmp_int)函数的放回值大于0,我们就交换一下两个数。

void my_sort(void* base, size_t sz, size_t width, int (cmp)(void, void*))

{

//函数里面实则还是冒泡排序

int i = 0;

for (i = 0; i < sz; 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函数,其实函数里面需要循环4次才行,因为是4个字节的数据嘛

Exch((char*)base + j * width, (char*)base + (j + 1) * width, width);

}

}

}

}

随着j的增加,我们比较的数据也一个个的往后移,特别注意(char*) base + j * width,我们在使用base时,必须先要进行强制类型转换,这样再进行加减操作才可以。因为 base的类型是 void * 类型,没有具体的大小。强制类型转换后,再加上j*width个字节,这样就能找到数组中一个个的元素。

接下来就是函数Exch的实现,这个函数就是交换两个数的位置用的,(exchange)。上面的if语句如果成立,我们就调用函数Exch,去交换两个数的位置,传参的话,跟if语句里面的参数一样的,毋庸置疑。只是我们在传参的时候,还需要传第三个参数width,因为我们调用函数Exch后,函数里面一次交换,只能交换1个字节的内容。有小伙伴就会问,我一次直接交换4个字节的内容,这不是简单的多了嘛。。。。

对于整形数组,一次直接交换4个字节的内容,当然简单了,但是我们需要交换其他数据类型的时候呢,难道还要重新写一遍my_sort吗??是吧,所以,1个字节慢慢交换,循环width次就行,这样写出来的函数,才是通用的。

Exch函数的实现

void Exch(char* cmp1, char* cmp2, size_t width)

{

int i = 0;

for (i = 0; i < width; i++)

{

char tmp = *cmp1;

*cmp1 = *cmp2;

*cmp2 = tmp;

cmp1++, cmp2++; //逗号表达式,从左到右,依次执行

}

}

这里面就简单多了,就是创建一个临时变量 ,交换数据后,对应的地址加1即可,特别注意一下函数形参部分哦,为什么要写 char*。值得思考哦。

四、全部代码汇集

=================================================================

int cmp_int(const void* e1, const void* e2)

{

return (int)e2 - (int)e1;

}

void Exch(char* cmp1, char* cmp2, size_t width)

{

int i = 0;

for (i = 0; i < width; i++)

{

char tmp = *cmp1;

*cmp1 = *cmp2;

*cmp2 = tmp;

cmp1++, cmp2++; //逗号表达式,从左到右,依次执行

}

}

void my_sort(void* base, size_t sz, size_t width, int (cmp)(void, void*))

{

//函数里面实则还是冒泡排序

int i = 0;

for (i = 0; i < sz; 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函数,其实函数里面需要循环4次才行,因为是4个字节的数据嘛

Exch((char*)base + j * width, (char*)base + (j + 1) * width, width);

}

}

}

}

int main()

{

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

int sz = sizeof(arr) / sizeof(arr[0]);

my_sort(arr, sz, sizeof(arr[0]), cmp_int);

int i = 0;

for (i = 0; i < 10; i++)

printf("%d ", arr[i]);

return 0;

}

最后总结

搞定算法,面试字节再不怕,有需要文章中分享的这些二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析

最后再分享一份终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化

image

sort(arr, sz, sizeof(arr[0]), cmp_int);

int i = 0;

for (i = 0; i < 10; i++)

printf("%d ", arr[i]);

return 0;

}

最后总结

搞定算法,面试字节再不怕,有需要文章中分享的这些二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析

最后再分享一份终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化

[外链图片转存中…(img-QSsRnq9i-1720104995293)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值