C語(yǔ)言庫(kù)函數(shù)qsort的使用詳解
一、回調(diào)函數(shù)
C語(yǔ)言庫(kù)函數(shù)中的qsort的是一個(gè)回調(diào)函數(shù),回調(diào)函數(shù)就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。如果把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè) 函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。
二、庫(kù)函數(shù)qsort

void* base:要排序的數(shù)據(jù)的起始位置
size_t num:待排序數(shù)據(jù)的元素個(gè)數(shù)
size_t width:待排序的數(shù)據(jù)元素的大小,單位是字節(jié)
int(__cdecl*compare)(constvoid*elem1,constvoid*elem2):把比較函數(shù)的地址傳給cmp,e1和e2是要比較的兩個(gè)元素的地址。(__cdecl是函數(shù)調(diào)用約定)
注意:最后一個(gè)函數(shù)參數(shù)是一個(gè)函數(shù)指針,所以在調(diào)用庫(kù)函數(shù)qsort()的時(shí)候,傳的參數(shù)是比較函數(shù)的地址。

1、e1小于e2,返回值小于0;
2、e1等于e2,返回0;
3、e1大于e2,返回值大于0。
三、使用qsort排序整型數(shù)組
#include <stdlib.h>
#include <stdio.h>
int int_cmp(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;//升序排序
}
int main()
{
int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), int_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//打印0 1 2 3 4 5 6 7 8 9
}
return 0;
}庫(kù)函數(shù)qsort的比較函數(shù)是需要自己實(shí)現(xiàn)的,并且已經(jīng)給定了比較函數(shù)的兩個(gè)形參。因?yàn)閑1和e2是無(wú)類(lèi)型指針,不能解引用和加減。所以此處使用時(shí)需要先將指針類(lèi)型前置類(lèi)型轉(zhuǎn)換為int*,再進(jìn)行解引用操作。
此處可以加深回調(diào)函數(shù)的理解:int_cmp是本人來(lái)實(shí)現(xiàn)的,當(dāng)程序運(yùn)行到qsort函數(shù)時(shí),由庫(kù)函數(shù)qsort對(duì)int_cmp進(jìn)行調(diào)用。這就是回調(diào)函數(shù)。
四、使用qsort排序結(jié)構(gòu)體
1、使用qsort排序結(jié)構(gòu)體中的字符成員

先創(chuàng)建一個(gè)學(xué)生的結(jié)構(gòu)體類(lèi)型,定義一個(gè)結(jié)構(gòu)體類(lèi)型的學(xué)生數(shù)組,數(shù)組內(nèi)包含3名學(xué)生的信息。通過(guò)qsort函數(shù)進(jìn)行排序。在實(shí)現(xiàn)str_name_cmp函數(shù)時(shí),需要先將e1和e2先強(qiáng)制類(lèi)型轉(zhuǎn)換為struct Stu*類(lèi)型,由于strcmp函數(shù)的返回值剛好契合str_name_cmp函數(shù),可以直接使用return將返回值帶回。通過(guò)打印可以發(fā)現(xiàn)三名同學(xué)已經(jīng)按ASCII碼完成排序。
2、使用qsort排序結(jié)構(gòu)體中的整型成員
#include <stdlib.h>
#include <stdio.h>
struct Stu
{
char name[20];
int age;
};
int str_age_cmp(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",17},{"wangwu",22} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), str_age_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", s[i].age);//輸出17 18 22
}
return 0;
}排序結(jié)構(gòu)體整型成員和排序整型數(shù)組、結(jié)構(gòu)體字符成員方式相似。
五、基于冒泡排序的庫(kù)函數(shù)qsort的模擬實(shí)現(xiàn)
1、使用改寫(xiě)函數(shù)排序整型數(shù)組
#include <stdlib.h>
#include <stdio.h>
int int_cmp(const void* e1, const void* e2)//比較函數(shù)
{
return *(int*)e1 - *(int*)e2;//升序排序
}
Swap(char* p1, char* p2, size_t width)
{
for (int i = 0; i < width; i++)//每個(gè)字節(jié)交換
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void qsort_bubble(void* base, size_t sz, size_t width, int(* compare)(const void* e1, const void* e2))
{//基于庫(kù)函數(shù)qsort進(jìn)行改寫(xiě)的冒泡排序
for (int i = 0; i < sz-1; i++)
{
int change = 0;
for (int j = 1; j < sz - i; j++)
{
//交換
if (compare((char*)base+(j-1)*width , (char*)base+j*width)>0)
{
Swap((char*)base + (j - 1) * width, (char*)base + j * width,width);
change = 1;
}
}
if (change == 0)
break;
}
}
int main()
{
int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort_bubble(arr, sz,sizeof(arr[0]),int_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}qsort_bubble函數(shù)中,采用冒泡排序的比較方式,形參模仿庫(kù)函數(shù)qsort中的形參。
在函數(shù)內(nèi)部調(diào)用compare時(shí)(compare是比較函數(shù)的地址),由于外部比較的數(shù)據(jù)類(lèi)型不可知,故使用最小內(nèi)置類(lèi)型char和數(shù)據(jù)類(lèi)型的長(zhǎng)度width來(lái)表示外部類(lèi)型所占字節(jié)。
2、使用改寫(xiě)函數(shù)排序結(jié)構(gòu)體中的字符成員
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct Stu//定義結(jié)構(gòu)體
{
char name[20];
int age;
};
int str_name_cmp(const void* e1, const void* e2)//字符的比較函數(shù)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
Swap(char* p1, char* p2, size_t width)//交換函數(shù)
{
for (int i = 0; i < width; i++)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void qsort_bubble(void* base, size_t sz, size_t width, int(*compare)(const void* e1, const void* e2))
{基于庫(kù)函數(shù)qsort進(jìn)行改寫(xiě)的冒泡排序
for (int i = 0; i < sz - 1; i++)
{
int change = 0;
for (int j = 1; j < sz - i; j++)
{
if (compare((char*)base + (j - 1) * width, (char*)base + j * width)>0)
{
Swap((char*)base + (j - 1) * width, (char*)base + j * width, width);
change = 1;
}
}
if (change == 0)
break;
}
}
int main()
{
struct Stu s[] = {{"zhangsan",18},{"lisi",17},{"wangwu",22}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), str_name_cmp);
for (int i = 0; i < sz; i++)
{
printf("%s ", s[i].name);
}
return 0;
}輸出結(jié)果lisi wangwu zhangsan,理解方式和上方例子一樣。
3、對(duì)庫(kù)函數(shù)qsort的總結(jié)
第一次使用庫(kù)函數(shù)qsort的時(shí)候,肯定會(huì)疑惑,為什么e1-e2的返回值大于0時(shí),升序排序;反之降序?
我們?cè)谀M實(shí)現(xiàn)的時(shí)候,在冒泡排序內(nèi)部調(diào)用compare這個(gè)函數(shù)地址,傳參時(shí),如果前一個(gè)元素的值大于后一個(gè)元素,那么傳入比較函數(shù),e1-e2>0,進(jìn)行交換,交換完畢后e1<e2,實(shí)現(xiàn)了升序排序!
如果要實(shí)現(xiàn)降序排序,在比較函數(shù)內(nèi)使用e2-e1即可,意思是后一個(gè)元素大于前一個(gè)元素,進(jìn)行交換,交換完畢后e1>e2,實(shí)現(xiàn)了降序排序!
六、力扣977#中庫(kù)函數(shù)qsort的使用

使用pow函數(shù)對(duì)數(shù)組元素逐個(gè)平方。由于素組內(nèi)存在負(fù)數(shù),所以平方后數(shù)組可能亂序,需要重新排序,這里可以使用庫(kù)函數(shù)qsort進(jìn)行排序。
int compare(const void* elem1,const void* elem2)//比較函數(shù)
{
return *(int*)elem1-*(int*)elem2;
}
int* sortedSquares(int* nums, int numsSize, int* returnSize){
*returnSize=numsSize;
for(int i=0;i<numsSize;i++)
{
nums[i]=pow(nums[i],2);
}
qsort(nums,numsSize,sizeof(nums[0]),compare);//庫(kù)函數(shù)qsort的使用
return nums;
}但是平常刷題是還是不建議無(wú)腦上qsort,需要根據(jù)題目要求合理的選擇排序算法。
到此這篇關(guān)于C語(yǔ)言庫(kù)函數(shù)qsort的使用的文章就介紹到這了,更多相關(guān)C語(yǔ)言庫(kù)函數(shù)qsort內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
嵌入式項(xiàng)目使用C語(yǔ)言結(jié)構(gòu)體位段特性實(shí)現(xiàn)斷言宏校驗(yàn)數(shù)據(jù)范圍有效性的方法
今天小編就為大家分享一篇關(guān)于嵌入式項(xiàng)目使用C語(yǔ)言結(jié)構(gòu)體位段特性實(shí)現(xiàn)斷言宏校驗(yàn)數(shù)據(jù)范圍有效性的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
在vs2010中,輸出當(dāng)前文件路徑與源文件當(dāng)前行號(hào)的解決方法
本篇文章是對(duì)在vs2010中,輸出當(dāng)前文件路徑與源文件當(dāng)前行號(hào)的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C/C++ Qt 數(shù)據(jù)庫(kù)與Chart歷史數(shù)據(jù)展示
這篇文章主要介紹了Qt利用Qchart組件展示數(shù)據(jù)庫(kù)中的歷史數(shù)據(jù)。文中的示例代碼講解清晰,具有一定的學(xué)習(xí)和工作價(jià)值,感興趣的小伙伴可以學(xué)習(xí)一下2021-12-12
C++實(shí)現(xiàn)LeetCode(37.求解數(shù)獨(dú))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(37.求解數(shù)獨(dú)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
c++ 內(nèi)聯(lián)函數(shù)和普通函數(shù)的區(qū)別
內(nèi)聯(lián)函數(shù)是c++為了提高程序的運(yùn)行速度做的改進(jìn),那么內(nèi)聯(lián)函數(shù)和普通函數(shù)的區(qū)別是什么,本文就來(lái)詳細(xì)的介紹一下,感興趣的朋友可以了解一下2021-05-05
C語(yǔ)言實(shí)現(xiàn)繪制貝塞爾曲線的函數(shù)
貝塞爾曲線,又稱(chēng)貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。本文將利用C語(yǔ)言實(shí)現(xiàn)繪制貝塞爾曲線的函數(shù),需要的可以參考一下2022-12-12

