摘要:一前言我們學習過的冒泡排序,插入排序,選擇排序等經典排序方法,為我們數據排序提供了穩定思路,但局限在于排序數據類型的單一。
? ?我們學習過的冒泡排序,插入排序,選擇排序等經典排序方法,為我們數據排序提供了穩定思路,但局限在于排序數據類型的單一。為了解決這一問題,c語言中提供了庫函數qsort解決。我們今天就通過自定義函數實現qsort的功能,排序方法采用基本的冒泡排序
我們需要傳入四個變量:base——待排序數組的首元素地址;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? num——數組內的元素個數;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? width——每個元素的大小(單位為字節);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?函數指針——傳入兩個數的地址,比較二者大小(需自己設計)
1.可以傳入任何類型的指針而不會報警告,適合我們實現任何數據類型排序的目的;
2.不可以對其進行解引用操作,除非通過強制類型轉換()確定其具體類型;
3.不可以對其進行加減運算,原因是不知道類型所以不知道步長,因此還是需要強制類型轉換
注意:都需要先進行強制類型轉換才可以解引用
int cmp_int(const void* e1, const void* e2){ return *(int*)e1 - *(int*)e2;}
char類型數據不可以用<>=進行比較,所以要用函數strcmp庫函數,頭文件為#include
int cmp_char(const void*e1, const void*e2){ return strcmp((char*)e1, (char*)e2);}
因為返回的是int類型,所以我們加入了判斷語句。用數的正負表示數的大小情況
int cmp_float(const void*e1, const void*e2){ if ((float*)e1 > (float*)e2) return 1; else if ((float*)e1 ==(float*)e2) return 0; else return -1;}
結構體數組元素不可以直接比較,必須先選出結構體某一內容進行比較
typedef struct book{ char name[20]; int prince; }b;//重命名struct book為bint cmp_stru_price(const void*e1, const void*e2){ return ((b*)e1)->prince - ((b*)e2)->prince;}
注意!!!(b*)e1外面的括號不可以省略,因為->的優先級比強制類型轉換高
首先思考一個問題:既然傳入的指針為void*類型,如何實現步長的確定?聰明的科學家想到利用width作為我們的標準
void bubble_sort(void*base,int sz,int width,int(*cmp)(void*,void*)){ int i; int j; for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1-i; j++) { if (cmp((char*)base + width*j, (char*)base + width*(j + 1))>0) { swap((char*)base + width*j, (char*)base + width*(j + 1),width); } } }}
1.int(*)(void*,void*)是一個函數指針,指向我們之前設計的大小比較函數
2.在使用base的時候要先強制類型轉換才可以作加減運算
3.漂亮的地方在于,不管實際傳入的base是什么類型,我們都將其轉化為char*類型的指針,因為char*的步長最小為1,加上width就可以準確指向下一個?
以int為例,width為4,所及就可以指向下一個元素
?
?
void swap(char*buff1,char*buff2,int width){ int i; for (i = 0; i < width; i++) { int tmp = *buff1; *buff1 = *buff2; *buff2 = tmp; buff1++; buff2++; }}
值得關注的是,交換不是一次就可以了,因為我們現在是char*類型的指針,如上圖所畫,一次只能交換一格,如交換int的,要交換4次
1.函數指針的使用,使我們每次只需導入大小比較函數的地址即可,而不必寫多個函數,分別含有不同的大小比較函數,減少了重復代碼的出現
?2.width的使用相當于告訴了我們進行比較的數組元素的類型,滿足我們實現各種數據類型排序的需求
3.void*函數海納百川,方便了我們的輸入,只是注意在使用時的強制類型轉化,否則無法使用
希望上述的總結對大家的理解有幫助,也更好的欣賞回調函數(這里為用函數指針調用函數)的魅力。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/118801.html
摘要:故使用無具體類型,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算解引用,整數等。求指針所占字節而不是解引用訪問權限大小。數組就是整個數組的大小,數組元素則是數組元素的大小,指針大小都為。 ...
摘要:參數含義上圖是函數各個參數的含義,讓我們一個個來看。使用方式頭文件要使用函數我們首先需要引用一個頭文件的實現函數給函數規定了特定的參數。因此我們設計函數時要嚴格遵守其參數設定。 目錄 1.參數含義 1.首元素地址base 2.元素個數num 3.元素大小size 4.自定義比較函數compa...
摘要:回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。 目錄 前言無類型指針結構體指針枚舉變量指針函數...
摘要:如果你把函數的指針地址作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。 ...
閱讀 3392·2021-09-22 15:17
閱讀 2740·2021-09-02 15:15
閱讀 1749·2019-08-30 15:54
閱讀 2000·2019-08-30 14:02
閱讀 2529·2019-08-29 16:58
閱讀 2988·2019-08-29 16:08
閱讀 1330·2019-08-26 12:24
閱讀 1653·2019-08-26 10:41