摘要:我們以冒泡排序?yàn)槔M實(shí)現(xiàn)函數(shù)。交換每單位字節(jié)對(duì)于的二進(jìn)制序列這樣,冒泡排序就能排序多種數(shù)據(jù)類型,模擬實(shí)現(xiàn)了函數(shù),當(dāng)然也可以使用其他的排序方法模擬實(shí)現(xiàn)函數(shù)。
??前面的話??
大家好!對(duì)于排序有許多中方法,比如冒泡排序,選擇排序,希爾排序,插入排序,堆排序等等,但是怎樣能夠使用一個(gè)函數(shù)能夠?qū)Χ鄠€(gè)數(shù)據(jù)類型進(jìn)行排序呢?無(wú)所不知的C語(yǔ)言開(kāi)發(fā)者提供了一個(gè)qsort
函數(shù),它能夠?qū)Χ喾N數(shù)據(jù)類型進(jìn)行排序,實(shí)現(xiàn)各種數(shù)據(jù)類型的快速排序,這篇文章介紹qsort
函數(shù)的使用及其模擬qsort
函數(shù)的實(shí)現(xiàn)(基于冒泡排序)。
?博客主頁(yè):未見(jiàn)花聞的博客主頁(yè)
?歡迎關(guān)注?點(diǎn)贊?收藏??留言?
?本文由未見(jiàn)花聞原創(chuàng),CSDN首發(fā)!
?首發(fā)時(shí)間:?2021年9月7日?
??堅(jiān)持和努力一定能換來(lái)詩(shī)與遠(yuǎn)方!
?參考書籍:?《明解C語(yǔ)言》?《C primer plus》
?參考在線編程網(wǎng)站:?牛客網(wǎng)?力扣
?作者水平很有限,如果發(fā)現(xiàn)錯(cuò)誤,一定要及時(shí)告知作者哦!感謝感謝!
博主的碼云gitee,平常博主寫的程序代碼都在里面。
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
實(shí)現(xiàn)多個(gè)數(shù)據(jù)類型的快速排序。
void
無(wú)返回值void*
無(wú)類型指針,可以接受任何指針類型,但是不能進(jìn)行解引用,不能進(jìn)行運(yùn)算。該參數(shù)用來(lái)接受需要排序數(shù)組的首地址。size_t
類型,本質(zhì)上為無(wú)符號(hào)整型類型,該參數(shù)接受數(shù)組中元素的數(shù)量。size_t
類型,本質(zhì)上無(wú)符號(hào)整型類型,該參數(shù)接受數(shù)組中元素的內(nèi)存大小,單位為字節(jié)。int
,擁有2個(gè)參數(shù)的函數(shù),其實(shí)這兩個(gè)參數(shù)類型都為const void
指針。該函數(shù)用來(lái)比較兩個(gè)地址對(duì)應(yīng)的元素的大小。該參數(shù)用來(lái)回調(diào)compare
所指向的函數(shù),是實(shí)現(xiàn)多數(shù)據(jù)類型排序的核心。在qsort
函數(shù)中,其中一個(gè)參數(shù)是函數(shù)指針,指向一個(gè)用來(lái)比較兩個(gè)元素大小的函數(shù),不妨記該函數(shù)的第一個(gè)參數(shù)為e1
,第二個(gè)參數(shù)為e2
,兩個(gè)參數(shù)均為只可讀無(wú)類型指針,該函數(shù)返回值類型為int
,記為x
:
e1
指向的元素大于e2
指向的元素。e1
指向的元素等于e2
指向的元素。e1
指向的元素小于e2
指向的元素。實(shí)現(xiàn)整型類型比較的compare函數(shù)
:
如果qsort
需要實(shí)現(xiàn)實(shí)現(xiàn)升序:
//升序int compare(const void* a, const void* b){ return (*(int*)a - *(int*)b);}
那需要實(shí)現(xiàn)降序呢?
其實(shí)很簡(jiǎn)單,將上面return (*(int*)a - *(int*)b);
改為return (*(int*)b - *(int*)a);
就可以了。
實(shí)現(xiàn)浮點(diǎn)數(shù)比較的compare函數(shù)
:
int compare_dou(const void* a, const void* b){ double com = (*(double*)a - *(double*)b); //防止數(shù)據(jù)發(fā)生截?cái)嘣斐膳判蚪Y(jié)果錯(cuò)誤 if (com > 0) return 1; else if (com < 0) return -1; else return 0;}int compare_fla(const void* a, const void* b){ float com = (*(float*)a - *(float*)b); //防止數(shù)據(jù)發(fā)生截?cái)嘣斐膳判蚪Y(jié)果錯(cuò)誤 if (com > 0) return 1; else if (com < 0) return -1; else return 0;}
實(shí)現(xiàn)字符類型和字符串比較的compare函數(shù)
:
int compare(const void* a, const void* b){ return (*(char*)a - *(char*)b);}
實(shí)現(xiàn)結(jié)構(gòu)體類型比較compare函數(shù)
:
//參考結(jié)構(gòu)體struct stu{ char name[20]; int age; double score;};
int compare_stu(const void* a, const void* b){ //如果是字符串 return strcmp(((struct stu*)a)->name, ((struct stu*)b)->name); //如果整型 //return (((struct stu*)a)->age - ((struct stu*)b)->age); //如果是浮點(diǎn)型 //float com = (*(float*)a - *(float*)b); //防止數(shù)據(jù)發(fā)生截?cái)嘣斐膳判蚪Y(jié)果錯(cuò)誤 //if (com > 0) // return 1; /*else if (com < 0) return -1; else return 0;*/}
測(cè)試主函數(shù)
#include #include #include int main (){//test;}
測(cè)試1:整數(shù)排序
void test1(){ int arr[] = { 2,8,6,12,3,86,1,42,66,22,98,88 }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(int); sz_t i = 0; printf("數(shù)組排序前:/n"); for (i = 0; i < number; i++) { printf("%d ", arr[i]); } qsort(arr, number, size, compare); printf("/n數(shù)組排序后:/n"); for (i = 0; i < number; i++) { printf("%d ", arr[i]); }}
數(shù)組排序前:2 8 6 12 3 86 1 42 66 22 98 88數(shù)組排序后:1 2 3 6 8 12 22 42 66 86 88 98D:/gtee/C-learning-code-and-project/練習(xí)使用qsort/Debug/練習(xí)使用qsort.exe (進(jìn)程 37064)已退出,代碼為 0。按任意鍵關(guān)閉此窗口. . .
測(cè)試2:雙精度浮點(diǎn)數(shù)排序
void test2(){ double arr[5] = { 3.5,8.9,9.2,4.8,2.1 }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(double); sz_t i = 0; printf("數(shù)組排序前:/n"); for (i = 0; i < number; i++) { printf("%.2lf ", arr[i]); } qsort(arr, number, size, compare_dou); printf("/n數(shù)組排序后:/n"); for (i = 0; i < number; i++) { printf("%.2lf ", arr[i]); }}
數(shù)組排序前:3.50 8.90 9.20 4.80 2.10數(shù)組排序后:2.10 3.50 4.80 8.90 9.20D:/gtee/C-learning-code-and-project/練習(xí)使用qsort/Debug/練習(xí)使用qsort.exe (進(jìn)程 9984)已退出,代碼為 0。按任意鍵關(guān)閉此窗口. . .
測(cè)試3:結(jié)構(gòu)體中字符串排序測(cè)試
void test3(){ struct stu arr[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(arr[0]); sz_t i = 0; printf("數(shù)組排序前:/n"); for (i = 0; i < number; i++) { printf("%s ", arr[i].name); } qsort(arr, number, size, compare_stu); printf("/n數(shù)組排序后:/n"); for (i = 0; i < number; i++) { printf("%s ", arr[i].name); }}
數(shù)組排序前:zhangsan lisi wangwu數(shù)組排序后:lisi wangwu zhangsanD:/gtee/C-learning-code-and-project/練習(xí)使用qsort/Debug/練習(xí)使用qsort.exe (進(jìn)程 29572)已退出,代碼為 0。按任意鍵關(guān)閉此窗口. . .
經(jīng)過(guò)對(duì)qsort
函數(shù)的了解,我們發(fā)現(xiàn)該函數(shù)能夠?qū)Χ喾N數(shù)據(jù)類型進(jìn)行排序取決于傳入的函數(shù)指針參數(shù)。我們以冒泡排序?yàn)槔M實(shí)現(xiàn)qsort
函數(shù)。
先來(lái)看看冒泡排序函數(shù)
#define _CRT_SECURE_NO_WARNINGS 1#include //冒泡排序(int) 從小到大void bubble_sort(int* arr, int size){ int i = 0; for (i = 0; i < size - 1; i++) { int j = 0; int flag = 1;//判斷數(shù)據(jù)是否發(fā)生交換,默認(rèn)沒(méi)有發(fā)生交換 for (j = 0; j < size - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 0; } } if (flag) break; }}
如果需要對(duì)多種數(shù)據(jù)類型進(jìn)行排序,對(duì)應(yīng)上面的這個(gè)冒泡排序,它所接受的參數(shù)肯定是必須改的,因?yàn)橐邮芏喾N數(shù)據(jù)類型的指針,所以傳入的指針必須是無(wú)具體類型void
。函數(shù)內(nèi)部中循環(huán)排序的次數(shù)是沒(méi)有發(fā)生改變的,所以函數(shù)內(nèi)部的兩層循環(huán)是不用發(fā)生改變的,但是由于傳進(jìn)來(lái)的是void
型指針,無(wú)法進(jìn)行運(yùn)算和解引用,所以判斷語(yǔ)句是需要進(jìn)行改動(dòng)的。
對(duì)與if
語(yǔ)句中所對(duì)應(yīng)條件,我們可以調(diào)用compare
函數(shù),將數(shù)組的前一個(gè)元素與后一個(gè)元素比較,如果該函數(shù)返回值大于0,表示數(shù)組前面的元素比后面的元素大,如果進(jìn)行升序排列,我們需要對(duì)這兩個(gè)元素進(jìn)行交換。這個(gè)交換我們不妨封裝在一個(gè)swap
函數(shù)里,由于不知道數(shù)據(jù)類型,所以swap
函數(shù)的參數(shù)為兩個(gè)元素的無(wú)類型地址,交換的時(shí)候我們不妨強(qiáng)制轉(zhuǎn)換為char*
類型,因?yàn)?code>char類型大小為1
字節(jié),根據(jù)需要交換元素的大小,我們一個(gè)一個(gè)地將每個(gè)單位字節(jié)的二進(jìn)制序列交換,這樣就完成了交換。對(duì)于如何得到相鄰元素的首地址,同理我們先可以將傳入指針強(qiáng)制轉(zhuǎn)換為char*
類型任何根據(jù)元素內(nèi)存大小,計(jì)算的出每個(gè)元素的地址。比如數(shù)組元素內(nèi)存大小為width
,則相鄰兩元素地址可以表示為(char*)val + j * width, (char*)val + (j + 1) * width
。
知道了冒泡排序哪個(gè)地方需要改裝,我們來(lái)試著動(dòng)手實(shí)踐一下。
typedef unsigned int sz_t;
void bubble_qsort(void* val, sz_t size, sz_t width, int (*cmp)(const void* p1, const void* p2)){ sz_t i = 0; for (i = 0; i < size - 1; i++) { sz_t j = 0; sz_t flag = 1; for (j = 0; j < size - 1 - i; j++) { if (cmp((char*)val + j * width, (char*)val + (j + 1) * width) > 0) { swap((char*)val + j * width, (char*)val + (j + 1) * width, width); flag = 0; } } if (flag) break; }}
void swap(char* buf1, char* buf2, sz_t width){ sz_t i = 0; for (i = 0; i < width; i++) { char tmp = *(buf1 + i); *(buf1 + i) = *(buf2 + i); *(buf2 + i) = tmp;//交換每單位字節(jié)對(duì)于的二進(jìn)制序列 }}
這樣,冒泡排序就能排序多種數(shù)據(jù)類型,模擬實(shí)現(xiàn)了qsort
函數(shù),當(dāng)然也可以使用其他的排序方法模擬實(shí)現(xiàn)qsort
函數(shù)。
測(cè)試主函數(shù)
#include #include #include int main (){//test;}
測(cè)試1:整數(shù)排序
void test1(){ int arr[] = { 2,8,6,12,3,86,1,42,66,22,98,88 }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(int); sz_t i = 0; printf("數(shù)組排序前:/n"); for (i = 0; i < number; i++) { printf("%d ", arr[i]); } bubble_qsort(arr, number, size, compare); printf("/n數(shù)組排序后:/n"); for (i = 0; i < number; i++) { printf("%d ", arr[i]); }}
數(shù)組排序前:2 8 6 12 3 86 1 42 66 22 98 88數(shù)組排序后:1 2 3 6 8 12 22 42 66 86 88 98D:/gtee/C-learning-code-and-project/練習(xí)使用qsort/Debug/練習(xí)使用qsort.exe (進(jìn)程 10620)已退出,代碼為 0。按任意鍵關(guān)閉此窗口. . .
測(cè)試2:雙精度浮點(diǎn)數(shù)排序
void test2(){ double arr[5] = { 3.5,8.9,9.2,4.8,2.1 }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(double); sz_t i = 0; printf("數(shù)組排序前:/n"); for (i = 0; i < number; i++) { printf("%.2lf ", arr[i]); } bubble_qsort(arr, number, size, compare_dou); printf("/n數(shù)組排序后:/n"); for (i = 0; i < number; i++) { printf("%.2lf ", arr[i]); }}
數(shù)組排序前:3.50 8.90 9.20 4.80 2.10數(shù)組排序后:2.10 3.50 4.80 8.90 9.20D:/gtee/C-learning-code-and-project/練習(xí)使用qsort/Debug/練習(xí)使用qsort.exe (進(jìn)程 34200)已退出,代碼為 0。按任意鍵關(guān)閉此窗口. . .
測(cè)試3:結(jié)構(gòu)體中字符串排序測(cè)試
void test3(){ struct stu arr[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} }; sz_t number = sizeof(arr) / sizeof(arr[0]); sz_t size = sizeof(arr[0]
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/119676.html
摘要:故使用無(wú)具體類型,又稱通用類型,即可以接收任意類型的指針,但是無(wú)法進(jìn)行指針運(yùn)算解引用,整數(shù)等。求指針?biāo)甲止?jié)而不是解引用訪問(wèn)權(quán)限大小。數(shù)組就是整個(gè)數(shù)組的大小,數(shù)組元素則是數(shù)組元素的大小,指針大小都為。 ...
摘要:目錄一函數(shù)是什么二使用排序以升序?yàn)槔P(guān)于型指針整形數(shù)組排序字符數(shù)組排序字符指針數(shù)組排序結(jié)構(gòu)體數(shù)組排序浮點(diǎn)型數(shù)組排序三使用冒泡排序思想模擬實(shí)現(xiàn)函數(shù)什么是冒泡排序冒泡排序代碼使用冒泡排序思想模 目錄 一.qsort函數(shù)是什么 ?二.使用qsort排序-以升序?yàn)槔?? ? ??關(guān)于void*型指針...
摘要:參數(shù)含義上圖是函數(shù)各個(gè)參數(shù)的含義,讓我們一個(gè)個(gè)來(lái)看。使用方式頭文件要使用函數(shù)我們首先需要引用一個(gè)頭文件的實(shí)現(xiàn)函數(shù)給函數(shù)規(guī)定了特定的參數(shù)。因此我們?cè)O(shè)計(jì)函數(shù)時(shí)要嚴(yán)格遵守其參數(shù)設(shè)定。 目錄 1.參數(shù)含義 1.首元素地址base 2.元素個(gè)數(shù)num 3.元素大小size 4.自定義比較函數(shù)compa...
閱讀 3290·2021-09-09 11:39
閱讀 1237·2021-09-09 09:33
閱讀 1139·2019-08-30 15:43
閱讀 555·2019-08-29 14:08
閱讀 1740·2019-08-26 13:49
閱讀 2386·2019-08-26 10:09
閱讀 1552·2019-08-23 17:13
閱讀 2290·2019-08-23 12:57