排序函數qsort和sort用法與區別簡談

       qsort和sort是兩個編譯器自帶的快速排序方法,相比自己寫一個排序算法,不僅更簡單,效率也往往更高。qsort需要引入頭文件<stdlib.h>,sort則需要<algorithm>。

       先說相對略微簡單的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是<string.h>中的函數,用於比較字符串大小,如果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返回值的正負決定是否交換,負數不交換,正數交換,爲了匹配這個特性,一般用減法判斷大小。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章