排序函数qsort和sort用法与区别简谈

       qsort和sort是两个编译器自带的快速排序方法,相比自己写一个排序算法,不仅更简单,效率也往往更高。qsort需要引入头文件,sort则需要

       先说相对略微简单的sort,原型就不写了,直接举int数组的例子吧


int a[10] = {5,8,9,1,4,7,6,3,5,8};
sort(a,a+10,com); 

       其中有三个参数,a代表首元素地址(数组名就是首元素地址),a+10代表末元素后一位的地址,这两个参数表示了待排序的范围,所以也可以写a+1,a+5等等进行局部排序。第三个参数是个函数,如果省略默认按从小到大排序。接下来就举个自定义的比较函数com的例子。

bool com(int a,int b)    { return a < b; } 

       传递参数只能使用int直接传值,或者int&传递引用,不能int*传递指针。如果函数返回值为true,则不必交换元素,如果返回值为false,则进行交换,所以这个就是从小到大的排序啦。

       下面介绍qsort,为了体现两者的不同,这里举字符串的例子。

char* fruit[5] = {"apple","pineapple","banana","peach","melon"};
qsort(fruit,5,sizeof(fruit[0]),com);

       qsort需要四个参数,第一个仍然是首元素地址,第二个是元素数量,第三个是每个元素的大小,可以用sizeof(fruit[0])获取,因为fruit其实是个存储char*指针的数组,所以sizeof(char*)也可以,(注意:apple等字符串并不储存在fruit里面,而是在另一块内存,fruit只是存储了指向它们的指针,所以才能交换,如果写成char fruit[5][10],fruit就变成存储apple等字符串的数组了,而交换字符串是没有定义的, 会报错!!!),第四个参数是交换函数,省略也是默认从小到大排序。

       接下来是qsort和sort最大的不同,就是这个自定义的比较函数,其原型只有一种写法,返回值必须是int,参数不仅必须按引用传递,而且必须是void指针,不能具体写int*char*什么的,甚至连const都不能省略!!!要求可是比sort严格多

int com(const void* a,const void* b)    { return strcmp(*(char**)a,*(char**)b); }

       再看函数定义,首先看到的不同是,没有了>和<符号,还有就是一堆*。首先说和sort不同的是,qsort不再用>和<的真假判断是否交换,它一般用的是减法,例如比较两个int类型时要这么写,如果结果是负数就不用交换,如果结果是正数就进行交换。(按结果正负决定是否交换,而不是sort的真假!!!)于 strcmp也是这样,strcmp是中的函数,用于比较字符串大小,如果a比b小结果是负数,a=b结果是0,a比b大 则结果是正数,所以说原理和int型没有区别。(第一个重要不同,一定要注意!如果两个函数的规则搞反的话就是瞎jb排了!)

return *(int*)a - *(int*)b;

       然后看那一堆*,因为qsort的比较函数com按地址传递,所以我们得到的a和b实际上是指向fruit元素的指针,而fruit元素本身又是指向apple等字符串的指针,所以a和b实际上是指向指针的指针,也就是char**型,(可以这么理解char*代表a指向的元素是 char*型,第二个*代表a是指针,连起来就是char**啦),所以首先要使用(char**)a类型转换为本来的模样,然后再进行解引用,所以*(char**)a其实就是fruit里的元素,由于是按指针传递,修改*(char**)a就等于修改fruit,所以又要求必须加const来保证不修改原数组。

      最后总结一下其实只要搞清楚两个重要区别就行啦,sort的比较函数按值或引用传递参数,然后根据com函数的返回值是true还是false决定是否交换,true不交换,false交换,为了匹配这个特性,一般用<>号判断大小。qsort的比较函数按void指针传递,所以多一部类型转换和解引用,然后根据com返回值的正负决定是否交换,负数不交换,正数交换,为了匹配这个特性,一般用减法判断大小。


你可能感兴趣的:(C/C++学习笔记)