本文主要讲述了是如何理解冒泡排序算法以及将冒泡排序进一步优化,达到可以接近模拟qsort函数的目的。
主要分为三大板块:
1:如何理解冒泡排序
2:qsort函数是如何使用
3:试着模拟qsort函数
1 如何理解冒泡排序
冒泡排序,简单地来说就是相邻的两个数字比大小,然后从左到右或者从右到左一直比下去,重复很多趟,直到将一组数字呈现从左到右依次递减,或者从左到右依次递增。
下面看冒泡排序算法:
调试结果:
思路是调用了两个for循环嵌套进行排序,比较简单。
2 qsort函数是如何使用
先看源代码:
简化一下便是:
第一个元素base代表的是需要排序的一组数据的首地址
第二个元素 sz代表的是需要排序的数据的个数
第三个元素代表的是需要排序的一组数据的里面的单个元素类型所占的字节数
第四个元素是一个函数指针,需要使用者自己创建一个函数传入,当e1的值大于e2时返回>0的数,当e1<e2时返回<0的数,当e1=e2时返回0
使用的时候要包含头文件<stdlib.h>
使用时的关键是自己需要去创建一个函数用来判断不同类型的一组数据中相邻的两个元素大小,比如说传入一组结构体数组,需要去排序,则需要自己建立一个函数去判断结构体数组中相邻两个元素大小。
举个例子:
我建立了一组结构体数组,然后我要根据结构体数组中的判断成员name的大小来进行排序,则我需要自己创建一个关于比较name中字符串大小的函数,返回值分别是>0和<=0。
则建立函数
然后调用qsort函数,传入函数:
这样就根据结构体成员中的name的大小来进行排序了
结果是:
3:试着模拟qsort函数
这里想要利用前面的冒泡排序的思想去模拟一下qsort函数,虽然达不到快排的目的,但是能达到对任何类型传进来的数据进行排序。
想要对任何传入任何类型的数据进行排序,首先先看前看qsort函数的三个元素:
第一个元素base指针,由于base是无类型的指针,所以可以接收任何类型的指针,然后再进行强制类型转换来进一步操作
第二个元素是需要排序的个数,只需要计算出个数就行
第三个元素是该传入类型的一组数据的单个元素所占字节数 ,即用sizeof操作符来进行计算便可
(第四个元素创建函数在下文)
然后就是将bubble_sort(冒泡排序)进行优化:
这里在冒泡排序的第二重for循环里面的if条件判断语句这里进行修改,将上面第四个元素接收的cmp函数进行调用,并且强制类型转换base为char*然后进行+width(也就是得到每个该未知类型的元素的地址,(比如说传入整形数组,那么(char*)base+width就等于一个元素的地址加4,下一个元素便是(char*)base+8,也就是得到下一个整形元素然后进行比较大小。)
然后建立一个Swap进行每一次判断if的条件大于0后对每两个元素进行一个字节一个字节的内容进行互换:
这里传入的width就是每一个元素的所占字节数,(也就是说传入类型是int就对4个字节里面进行一个字节一个字节的内容进行互换,若是结构体类型所占12个字节则对每相邻的两个元素所占的12个字节的内容进行一个字节一个字节的互换)
接下来就是模拟qsort函数时里面的第四个元素各类型cmp函数的创建。
整形数组类型:
字符串的字符类型
结构体里面的浮点数类型
结构体里面的整形类型
结构体里面的字符串类型
这就是借助了冒泡排序算法思想进一步模拟了qsort函数对任意类型的一组数据进行排序,虽然达不到快排的目的,但是能达到对任意类型数据进行排序。