??個(gè)人主頁(yè):修修修也
??所屬專欄:C語(yǔ)言
??操作環(huán)境:Visual Studio 2022
?
目錄
一.qsort()函數(shù)的基本信息及功能
二.常見的排序算法及冒泡排序
三.逐一解讀qsort()函數(shù)的參數(shù)及其原理
1.void* base
2.size_t num
3.size_t size
4.int (*compar)(const void*,const void*)
四.使用qsort()函數(shù)完成整形,結(jié)構(gòu)體的排序(演示)
1.使用qsort()函數(shù)完成對(duì)一維整形數(shù)組的排序:
2.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體的排序:
1>.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡排序
2>.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體按姓名排序
?五.套用冒泡算法,改造并模擬實(shí)現(xiàn)qsort()函數(shù)
1.bubble_sort()函數(shù)定義及參數(shù)
2.bubble_sort()函數(shù)函數(shù)體:
3.bubble_sort()函數(shù)中的回調(diào)函數(shù)Swap():
六.使用bubble_sort()函數(shù)完成整形,結(jié)構(gòu)體的排序(演示)
1.使用bubble_sort()函數(shù)完成對(duì)一維整形數(shù)組的排序:
2.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體的排序:
1>.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡排序
?2>.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體按姓名排序
一.qsort()函數(shù)的基本信息及功能
我們?nèi)粘I钪薪?jīng)常能碰到需要給一組數(shù)據(jù)排序的情況,如將班上同學(xué)的身高從大到小排序,將淘寶上的商品價(jià)格從低到高排序,將班上的同學(xué)姓名按首字母順序排序......隨著科學(xué)技術(shù)的發(fā)展,現(xiàn)在這些工作完全可以交給excel一鍵完成,那么電腦是根據(jù)什么程序完成這些排序的?
接下來我們就來給大家介紹一下C語(yǔ)言庫(kù)函數(shù)中可以“給萬物排序”的qsort()函數(shù):
先來看一下qsort()函數(shù)(quick sort)在百度百科中的定義:
因此,qsort()函數(shù)是一個(gè)C語(yǔ)言編譯器函數(shù)庫(kù)自帶的排序函數(shù),它可以對(duì)指定數(shù)組(包括字符串,二維數(shù)組,結(jié)構(gòu)體等)進(jìn)行排序。
二.常見的排序算法及冒泡排序
我們熟知的數(shù)組排序的算法有很多,如冒泡排序,選擇排序,直插排序,希爾排序,并歸排序,快速排序等,具體八大算法的實(shí)現(xiàn)可以移步這篇博客【數(shù)據(jù)結(jié)構(gòu)】八大排序算法
了解了這些種類繁多的排序算法后,我們希望能夠使用一種較為簡(jiǎn)單的排序算法來實(shí)現(xiàn)qsort函數(shù)的功能,來模擬實(shí)現(xiàn)同樣具有可以排序數(shù)組,字符串,結(jié)構(gòu)體功能的排序函數(shù)。如,我們可以使用冒泡排序的算法來實(shí)現(xiàn)具有排序字符串,二維數(shù)組,結(jié)構(gòu)體等功能的bubble_sort()函數(shù)。
如果還有不太熟悉冒泡排序的朋友可以移步這篇博客【C語(yǔ)言】冒泡排序詳解,里面有關(guān)于冒泡算法完全0基礎(chǔ)的詳解,這里就不多贅述了,我們?cè)谶@里直接演示一下冒泡排序的用法:
冒泡排序算法演示(以升序?yàn)槔?/p>
數(shù)組元素初始順序如下:
int arr[10] = { 3,1,5,9,7,6,4,8,0,2 };
冒泡排序(升序)運(yùn)行結(jié)果:
?冒泡排序(升序)完整代碼如下:
//冒泡排序<升序>
#include<stdio.h>
void print(int arr[])
{
int i = 0;
for (i = 0; i <= 9; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void sort(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for(j=0;j<sz-1-i;j++)
{
if (arr[j] > arr[j + 1])
{
int emp =arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = emp;
}
}
}
}
int main()
{
int arr[10] = { 3,1,5,9,7,6,4,8,0,2 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr);
sort(arr,sz);
print(arr);
return 0;
}
三.逐一解讀qsort()函數(shù)的參數(shù)及其原理
在搞清了我們的排序算法后,接下來為了進(jìn)一步模仿實(shí)現(xiàn)qsort()函數(shù),我們需要逐一解讀qsort()函數(shù)的參數(shù)及其作用,以便后續(xù)模仿實(shí)現(xiàn)它。
從cplusplus官網(wǎng)(cplusplus(C語(yǔ)言函數(shù)查詢網(wǎng)站))上我們可以看到qsort()函數(shù)是有四個(gè)參數(shù)的,如圖:
?而cplusplus官網(wǎng)對(duì)這四個(gè)變量的解釋是:
接下來我們一起來分析一下這四個(gè)參數(shù)及其作用:
1.void* base
void* base
即,qsort()函數(shù)需要的第一個(gè)參數(shù)是待排序數(shù)組的首元素地址,而void*的意思是它是一個(gè)無類型指針,而無類型的原因是我們希望它是一個(gè)可以排序很多種類數(shù)據(jù)的排序函數(shù),如果這里的指針類型固定,我們就只能對(duì)函數(shù)傳入固定類型的參數(shù)進(jìn)行排序了。
因此,要讓qsort()函數(shù)幫助我們排序,首先要告訴它這組數(shù)據(jù)的首地址在哪。
2.size_t num
size_t num
這個(gè)參數(shù)代表待排數(shù)組的元素個(gè)數(shù)。且因?yàn)?span style="color:#fe2c24;">元素個(gè)數(shù)恒為非負(fù)數(shù),因此該參數(shù)的數(shù)據(jù)類型是size_t(即無符號(hào)整形)。
計(jì)算數(shù)組元素個(gè)數(shù)常用的是sizeof,即數(shù)組元素個(gè)數(shù)=數(shù)組總長(zhǎng)度/數(shù)組首元素長(zhǎng)度,如:
size_t num=sizeof(arr)/sizeof(arr[0]);
因此,要讓qsort()函數(shù)幫助我們排序,我們還要告訴它這個(gè)數(shù)組一共有多少個(gè)元素。
3.size_t size
size_t size
?該參數(shù)意為待排數(shù)組中每個(gè)元素的長(zhǎng)度。同樣因?yàn)?span style="color:#fe2c24;">元素長(zhǎng)度恒為非負(fù)數(shù),因此參數(shù)的數(shù)據(jù)類型是size_t(無符號(hào)整形)。
計(jì)算數(shù)組元素長(zhǎng)度常用sizeof,及數(shù)組每個(gè)元素長(zhǎng)度=數(shù)組首元素的長(zhǎng)度,如:
size_t size=sizeof(arr[0]);
因此,要讓qsort()函數(shù)幫助我們排序,我們還要告訴它這個(gè)數(shù)組中的每個(gè)元素的長(zhǎng)度(即首元素的長(zhǎng)度)。
4.int (*compar)(const void*,const void*)
int (*compar)(const void*,const void*)
這個(gè)應(yīng)該算最難理解的部分了,不過我們一點(diǎn)一點(diǎn)來看,還是先畫個(gè)圖幫助大家理解吧:
?經(jīng)過我們的分析可知,該參數(shù)是一個(gè)函數(shù)指針,該指針指向的函數(shù)需要兩個(gè)無類型的指針作為參數(shù),同時(shí)該函數(shù)的返回值是一個(gè)int類型的整形。
他的作用是將傳進(jìn)來的兩個(gè)參數(shù)進(jìn)行比較,如果參數(shù)p1<參數(shù)p2,則返回一個(gè)小于0的數(shù),如果參數(shù)p1=參數(shù)p2,則返回0;如果參數(shù)p1>p2,則返回一個(gè)大于0的數(shù)。
注意!compar()函數(shù)的作用僅僅是比較兩個(gè)參數(shù)的大小,并通過返回值的形式告訴qsort()函數(shù)比較的結(jié)果,在運(yùn)行期間是不能更改參數(shù)1或參數(shù)2的值的,所以為保險(xiǎn)起見,我們可以給兩個(gè)參數(shù)前加上const修飾,來使參數(shù)指向的數(shù)值無法改變。
小tips:const修飾的指針,在*符號(hào)左邊即為固定指向的值不可改變,在*符號(hào)右邊則為固定指針指向的方向不可改變??梢院?jiǎn)記為:左定值,右定向。
compar()函數(shù)編寫樣例如下:
需要注意的是:這個(gè)指針指向的函數(shù)是由你自己編寫的,即qsort()函數(shù)會(huì)在其內(nèi)部調(diào)用你編寫的比較函數(shù),而這個(gè)比較函數(shù)如何比較qsort()函數(shù)傳遞的兩個(gè)參數(shù)是完全由你自己定義的。
在qsort()函數(shù)調(diào)用完compar()函數(shù)后,會(huì)接收到compar()返回的一個(gè)有符號(hào)的整型數(shù)字,當(dāng)接收到comper()返回大于0的數(shù)字時(shí),qsort()函數(shù)就會(huì)將這兩個(gè)元素做交換。而如果接收到comper()函數(shù)返回小于等于0的數(shù)時(shí),qsort()函數(shù)不對(duì)其進(jìn)行交換。
因此,在compar()函數(shù)使用*p1-*p2的方式直接返回結(jié)果數(shù)字時(shí),qsort()排出的序默認(rèn)會(huì)是升序。而如果你希望qsort()函數(shù)排出一個(gè)降序數(shù)組時(shí),那么就需要調(diào)換一下*p1和*p2的減法關(guān)系,直接返回*p2-*p1的值即可。
下面列舉一些大家常用的compar()比較函數(shù):
1.對(duì)一維數(shù)組進(jìn)行排序
int comper(const void*a,const void*b) { return *(int*)a-*(int*)b; }
2.對(duì)二維數(shù)組進(jìn)行排序
int comper(const void*a,const void*b) { return((int*)a)[0]-((int*)b)[0]; }
3.對(duì)字符串進(jìn)行排序
int comper(const void*p1,const void*p2) { return strcmp((char*)p2,(char*)p1); }
4.按結(jié)構(gòu)體中某個(gè)關(guān)鍵字排序(對(duì)結(jié)構(gòu)體一級(jí)排序):
structNode { double data; int other; }s[100]; int comper(constvoid*p1,constvoid*p2) { return(*(Node*)p2).data>(*(Node*)p1).data?1:-1; }
5.對(duì)結(jié)構(gòu)體中字符串進(jìn)行排序:
struct Node { int data; char str[100]; }s[100]; //按照結(jié)構(gòu)體中字符串str的字典序排序 int comper(const void*p1,const void*p2) { return strcmp((*(Node*)p1).str,(*(Node*)p2).str); }
四.使用qsort()函數(shù)完成整形,結(jié)構(gòu)體的排序(演示)
了解了qsort()函數(shù)的參數(shù)及其原理后,我們來嘗試使用它完成一些排序任務(wù),以此來熟悉qsort()函數(shù)的使用方法。
1.使用qsort()函數(shù)完成對(duì)一維整形數(shù)組的排序:
要使用qsort()函數(shù),就要先準(zhǔn)備好它需要的四個(gè)參數(shù),即數(shù)組的首地址,數(shù)組的長(zhǎng)度,數(shù)組每個(gè)元素的長(zhǎng)度,還有比較函數(shù)的地址(即函數(shù)名)。我們依次準(zhǔn)備好這四個(gè)參數(shù):
?接下來就可以調(diào)用qsort()函數(shù)查看結(jié)果了:
?可以看到,qsort()函數(shù)成功幫我們將該組整形排列成了升序。該部分完整代碼如下:
//使用qsort()函數(shù)排序一維數(shù)組
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int compar(const void* p1, const void* p2)
{
return ((*(int*)p1) - (*(int*)p2));
}
int main()
{
int arr[10] = { 3,1,5,9,7,6,4,8,0,2 };
size_t num = sizeof(arr) / sizeof(arr[0]);
size_t sz = sizeof(arr[0]);
qsort(arr, num, sz, compar);
int i=0;
for (i = 0; i < num; i++)
printf("%d ", arr[i]);
return 0;
}
2.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體的排序:
要使用qsort()函數(shù)排序結(jié)構(gòu)體,我們首先要創(chuàng)建一個(gè)結(jié)構(gòu)體變量,如下,我們先創(chuàng)建一個(gè)包含人名和年齡的結(jié)構(gòu)體變量:
?下面會(huì)以這個(gè)結(jié)構(gòu)體變量為例,分別實(shí)現(xiàn)使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡和按姓名的排序。
1>.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡排序
我們照例先準(zhǔn)備好它需要的四個(gè)參數(shù),即結(jié)構(gòu)體的首地址,結(jié)構(gòu)體的長(zhǎng)度,結(jié)構(gòu)體每個(gè)元素的長(zhǎng)度,還有比較函數(shù)的地址。我們依次準(zhǔn)備好這四個(gè)參數(shù):
?接下來就可以調(diào)用qsort()函數(shù)查看結(jié)果了:
?可以看到,qsort()函數(shù)幫助我們將該結(jié)構(gòu)體成功按年齡從小到大重新排序了。該部分完整代碼如下:
//使用qsort()函數(shù)按年齡排序結(jié)構(gòu)體
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//創(chuàng)建結(jié)構(gòu)體
struct Stu
{
char name[20];
int age;
};
//compar_按年齡排序
int compar_Stu_age(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int main()
{
struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} };
size_t num = sizeof(s) / sizeof(s[0]);
size_t sz = sizeof(s[0]);
qsort(s, num, sz, compar_Stu_age);
for (int i = 0; i < 3; i++)
{
printf("%s,%d\n", s[i].name, s[i].age);
}
return 0;
}
2>.使用qsort()函數(shù)完成對(duì)結(jié)構(gòu)體按姓名排序
我們照例先準(zhǔn)備好它需要的四個(gè)參數(shù),即結(jié)構(gòu)體的首地址,結(jié)構(gòu)體的長(zhǎng)度,結(jié)構(gòu)體每個(gè)元素的長(zhǎng)度,還有比較函數(shù)的地址。我們依次準(zhǔn)備好這四個(gè)參數(shù):
需要特別注意按姓名排序的排序函數(shù),因?yàn)?span style="color:#fe2c24;">按姓名排序本質(zhì)上是給字符串排序,所以我們借助strcmp()函數(shù)來比較兩個(gè)字符串的大小,并將比較的結(jié)果返回給qsort()函數(shù)。
有關(guān)strcmp()函數(shù)的相關(guān)信息如下:
?接下來就可以調(diào)用qsort()函數(shù)查看結(jié)果了:
?可以看到,qsort()函數(shù)按照名字順序(字典序)幫助我們成功排好了結(jié)構(gòu)體的順序,該部分完整代碼如下:
//使用qsort()函數(shù)按姓名排序結(jié)構(gòu)體
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//創(chuàng)建結(jié)構(gòu)體
struct Stu
{
char name[20];
int age;
};
//compar_按姓名排序
int compar_Stu_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int main()
{
struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} };
size_t num = sizeof(s) / sizeof(s[0]);
size_t sz = sizeof(s[0]);
qsort(s, num, sz, compar_Stu_name);
//打印結(jié)果
for (int i = 0; i < 3; i++)
{
printf("%s,%d\n", s[i].name, s[i].age);
}
return 0;
}
?五.套用冒泡排序算法,改造并模擬實(shí)現(xiàn)qsort()函數(shù)
通過上面的例子,我們已經(jīng)能夠熟練使用并足夠了解qsort()函數(shù)了,接下來我們就可以嘗試套用冒泡算法來試試實(shí)現(xiàn)bubble_sort()函數(shù)了:
1.bubble_sort()函數(shù)定義及參數(shù)
函數(shù)參數(shù)沒什么好說的,因?yàn)橐M實(shí)現(xiàn)qsort()函數(shù),因此直接仿照qsort()函數(shù)的參數(shù)即可:
void bubble_sort(void*base, size_t num,size_t sz,int(*compar)(const void*,const void*))
2.bubble_sort()函數(shù)函數(shù)體
函數(shù)體內(nèi)部邏輯整體參考冒泡排序,只在一小部分地方有略微的改動(dòng)。首先因?yàn)槲覀冊(cè)谡麄€(gè)bubble_sort()函數(shù)中都不知道base傳進(jìn)的參數(shù)到底是什么類型的,因此索性不去糾結(jié)數(shù)據(jù)的類型,干脆將他們統(tǒng)一視為一個(gè)字節(jié)一個(gè)字節(jié)的空間來進(jìn)行比較及交換,因此傳入bubble_sort()函數(shù)的指針統(tǒng)一強(qiáng)制類型轉(zhuǎn)換成char*類型,以便后續(xù)我們一個(gè)字節(jié)一個(gè)字節(jié)操作。該部分代碼及解析如下:
{
size_t i = 0;
for (i = 0; i < num - 1; i++)
{
size_t j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (compar((char*)base+j*sz,(char*)base+(j+1)*sz) > 0)
//因?yàn)闊o法確定base到底代表什么類型的指針,因此不如全部當(dāng)作字符(只占1字節(jié))指針來處理
{
//交換
Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz);
//交換思路同樣是一個(gè)字節(jié)一個(gè)字節(jié)交換
}
}
}
}
3.bubble_sort()函數(shù)中的回調(diào)函數(shù)Swap()
我們把原本冒泡排序中的交換步驟直接重新分裝成一個(gè)函數(shù),專門用來交換比較后需要交換的兩個(gè)元素,同樣因?yàn)?span style="color:#fe2c24;">我們并不知道該數(shù)據(jù)的類型,只知道該數(shù)據(jù)的大小sz,因此我們不如直接將兩個(gè)sz大小的字節(jié)內(nèi)容逐個(gè)一個(gè)字節(jié)一個(gè)字節(jié)逐一交換,這樣就能保證不論是什么類型的數(shù)據(jù),交換完都不會(huì)出現(xiàn)差錯(cuò)了。該部分代碼如下:
//交換函數(shù)
void Swap(char* buf1, char* buf2,int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
六.使用bubble_sort()函數(shù)完成整形,結(jié)構(gòu)體的排序(演示)
完成了bubble_sort()函數(shù)的編寫,接下來我們嘗試使用它來代替前面的qsort()函數(shù)給數(shù)組及結(jié)構(gòu)體進(jìn)行排序:
1.使用bubble_sort()函數(shù)完成對(duì)一維整形數(shù)組的排序
我們像之前使用qsort()那樣準(zhǔn)備好bubble_sort()所需要的四個(gè)參數(shù):
接下來就可以使用bubble_sort()函數(shù)查看結(jié)果了:
?可以看到,bubble_sort()函數(shù)按照整形大小幫我們排好了升序。該部分完整代碼如下:
//使用冒泡排序排列一維數(shù)組
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
void Swap(char* buf1, char* buf2,int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void*base, size_t num,size_t sz,int(*compar)(const void*,const void*))
{
size_t i = 0;
for (i = 0; i < num - 1; i++)
{
size_t j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (compar((char*)base+j*sz,(char*)base+(j+1)*sz) > 0)
{
Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz);
}
}
}
}
int compar(const void* p1, const void* p2)
{
return ((*(int*)p1) - (*(int*)p2));
}
int main()
{
int arr[10] = { 3,1,5,9,7,6,4,8,0,2 };
size_t num = sizeof(arr) / sizeof(arr[0]);
size_t sz = sizeof(arr[0]);
bubble_sort(arr, num, sz, compar);
int i = 0;
for (i = 0; i < num; i++)
printf("%d ", arr[i]);
return 0;
}
2.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體的排序
要使用bubble_sort()函數(shù)排序結(jié)構(gòu)體,我們首先要?jiǎng)?chuàng)建一個(gè)結(jié)構(gòu)體變量,如下,我們先創(chuàng)建一個(gè)包含人名和年齡的結(jié)構(gòu)體變量:
?下面會(huì)以這個(gè)結(jié)構(gòu)體變量為例,分別實(shí)現(xiàn)使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡和按姓名的排序。
1>.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體按年齡排序
我們照例先準(zhǔn)備好它需要的四個(gè)參數(shù),即結(jié)構(gòu)體的首地址,結(jié)構(gòu)體的長(zhǎng)度,結(jié)構(gòu)體每個(gè)元素的長(zhǎng)度,還有比較函數(shù)的地址。我們依次準(zhǔn)備好這四個(gè)參數(shù):
接下來就可以調(diào)用bubble_sort()函數(shù)查看結(jié)果了:
?可以看到,bubble_sort()函數(shù)幫助我們將該結(jié)構(gòu)體成功按年齡從小到大重新排序了。該部分完整代碼如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//交換函數(shù)
void Swap(char* buf1, char* buf2, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t sz, int(*compar)(const void*, const void*))
{
size_t i = 0;
for (i = 0; i < num - 1; i++)
{
size_t j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (compar((char*)base + j * sz, (char*)base + (j + 1) * sz) > 0)
{
Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz);
}
}
}
}
struct Stu
{
char name[20];
int age;
};
//compar_按年齡排序
int compar_Stu_age(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int main()
{
struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} };
size_t num = sizeof(s) / sizeof(s[0]);
size_t sz = sizeof(s[0]);
bubble_sort(s, num, sz, compar_Stu_age);
for (int i = 0; i < 3; i++)
{
printf("%s,%d\n", s[i].name, s[i].age);
}
return 0;
}
?2>.使用bubble_sort()函數(shù)完成對(duì)結(jié)構(gòu)體按姓名排序
我們照例先準(zhǔn)備好它需要的四個(gè)參數(shù),即結(jié)構(gòu)體的首地址,結(jié)構(gòu)體的長(zhǎng)度,結(jié)構(gòu)體每個(gè)元素的長(zhǎng)度,還有比較函數(shù)的地址(即函數(shù)名)。我們依次準(zhǔn)備好這四個(gè)參數(shù):
?接下來就可以調(diào)用bubble_sort()函數(shù)查看結(jié)果了:
可以看到,bubble_sort()函數(shù)按照名字順序(字典序)幫助我們成功排好了結(jié)構(gòu)體的順序,該部分完整代碼如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//交換函數(shù)
void Swap(char* buf1, char* buf2, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t sz, int(*compar)(const void*, const void*))
{
size_t i = 0;
for (i = 0; i < num - 1; i++)
{
size_t j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (compar((char*)base + j * sz, (char*)base + (j + 1) * sz) > 0)
{
Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz);
}
}
}
}
struct Stu
{
char name[20];
int age;
};
//compar_按姓名排序
int compar_Stu_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int main()
{
struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} };
size_t num = sizeof(s) / sizeof(s[0]);
size_t sz = sizeof(s[0]);
bubble_sort(s, num, sz, compar_Stu_name);
for (int i = 0; i < 3; i++)
{
printf("%s,%d\n", s[i].name, s[i].age);
}
return 0;
}
七.qsort()的核心:快速排序算法
快速排序的思想
快排算法的基本思想是:
- 通過一趟排序?qū)⒋艛?shù)據(jù)分割成獨(dú)立的兩部分
- 其中一部分?jǐn)?shù)據(jù)的關(guān)鍵字均比另一部分?jǐn)?shù)據(jù)的關(guān)鍵字小
- 可分別對(duì)這兩部分?jǐn)?shù)據(jù)繼續(xù)進(jìn)行排序,以達(dá)到整個(gè)序列有序的目的.
具體的快速排序算法是如何實(shí)現(xiàn)的,我放在另一篇博客中了,里面不僅有三種實(shí)現(xiàn)快排算法的方式,并且包含了如何使用非遞歸方式實(shí)現(xiàn)快排算法,這里有于篇幅有限,就不對(duì)贅述了,感興趣的朋友可以移步這篇博客:
【數(shù)據(jù)結(jié)構(gòu)】八大排序之快速排序算法https://blog.csdn.net/weixin_72357342/article/details/135059337
?
總結(jié)
以上就是關(guān)于qsort()函數(shù)及其模擬實(shí)現(xiàn)bubble_sort()函數(shù)的全部?jī)?nèi)容,希望能對(duì)大家有所幫助或有所啟發(fā),歡迎各位大佬在評(píng)論區(qū)或私信與我交流.
有關(guān)更多排序相關(guān)知識(shí)可以移步:
【數(shù)據(jù)結(jié)構(gòu)】八大排序算法https://blog.csdn.net/weixin_72357342/article/details/135038495?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22135038495%22%2C%22source%22%3A%22weixin_72357342%22%7D&fromshare=blogdetail
學(xué)海漫浩浩,我亦苦作舟!關(guān)注我,大家一起學(xué)習(xí),一起進(jìn)步!
相關(guān)文章推薦
【數(shù)據(jù)結(jié)構(gòu)】八大排序之堆排序算法
【數(shù)據(jù)結(jié)構(gòu)】八大排序之簡(jiǎn)單選擇排序
【數(shù)據(jù)結(jié)構(gòu)】八大排序之直接插入排序算法
【數(shù)據(jù)結(jié)構(gòu)】八大排序之希爾排序算法
【C語(yǔ)言】判斷字符類型的三種方法
【C語(yǔ)言】rand()函數(shù)(如何生成指定范圍隨機(jī)數(shù))
【C語(yǔ)言】memset()函數(shù)
【C語(yǔ)言】strlen()函數(shù)
【C語(yǔ)言】memcpy()函數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-739208.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-739208.html
到了這里,關(guān)于【C語(yǔ)言】qsort()函數(shù)詳解:能給萬物排序的神奇函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!