前言:一個普通的插入排序.算法
//// 插入排序默認從大到小//externvoidsort_insert_int(inta[],int len) {編程
int i, j;數組
for(i =1; i < len; ++i) {函數
intkey = a[j = i];學習
// 從小到大while(j >0&& a[j -1] < key) {測試
a[j] = a[j -1];spa
--j;視頻
}blog
a[j] = key;排序
}
}
這時候有人就想了, 那數組是 double 的, 那怎麼弄了. 也有一種解決方案
#definesort_insert(a, len) \ _Generic(a
, int* : sort_insert_int
, double* : sort_insert_double
, default: sort_insert_default) (a, len)
是否是有所啓發. 固然了. 對於上面是使用從大到小封裝. 那若是須要從小到大呢. 能夠這麼作
staticinlineint_compare_2(constintleft,constint key) {
returnleft - key;
} externvoidsort_insert_2(inta[],int len,
intcompare(constintleft,constint key)) {
int i, j;
for(i =1; i < len; ++i) {
intkey = a[j = i];
while(j >0&& compare(a[j -1], key) <0) {
a[j] = a[j -1];
--j;
}
a[j] = key;
}
}
單獨把比較的行爲抽象出來, 註冊進去. 是否是很開心.
細緻一點封裝
也許到這裏會更開心. 既然能經過高科技泛型模擬出來. 那咱們不也可使用舊科技弄弄.
typedefint(* compare_f)(constvoid* left,constvoid* key);staticinlineint_compare_3(constvoid* left,constvoid* key) {
return*(int*)left - *(int*)key;
}externvoidsort_insert_3_(void* data, size_t ez,int len, compare_f compare) {
char* a = data;
void* key;
int i, j;
if((key =malloc(ez)) == NULL)
return;
for(i =1; i < len; ++i) {
memcpy(key, &a[i * ez], ez);
for(j = i; j >0&& compare(&a[(j -1) * ez], key) <0; --j)
memcpy(&a[j * ez], &a[(j -1) * ez], ez);
if(j != i)
memcpy(&a[j * ez], key, ez);
}
free(key);
}#definesort_insert_3(a, len, compare) \ sort_insert_3_(a, sizeof(*(a)), len, (compare_f)compare)
是否是很巧妙, 一切都編程 void * 了. 固然了若是使用 C99 版本以上, 或者說用高版本的 GCC.
能夠寫的更好.
externvoidsort_insert_4_(void* data, size_t ez,int len, compare_f compare) {
char* a = data;
char key[ez];
int i, j;
for(i =1; i < len; ++i) {
memcpy(key, &a[i * ez], ez);
for(j = i; j >0&& compare(&a[(j -1) * ez], key) <0; --j)
memcpy(&a[j * ez], &a[(j -1) * ez], ez);
if(j != i)
memcpy(&a[j * ez], key, ez);
}
}
這裏用了 C99 的 VLA 特性. 不知道細心的同窗是否和思考. GCC 是怎麼實現 VLA 可變長數組呢.
撥開雲霧見青天, 咱們不妨來個實驗驗證一哈. 看下面測試代碼
#include #include /* * file : vla.c
* make : gcc -g -Wall -O2 -o vla.exe vla.c
*
*/intmain(intargc,char* argv[]) {
chara[10];
intb =7;
char c[b];
int* d =malloc(sizeof(int));
if(d == NULL)
exit(EXIT_FAILURE);
*d =1000;
chare[*d];
printf("%p : char a[10]\n", a);
printf("%p : int b\n", &b);
printf("%p : char c[b]\n", c);
printf("%p : int * d\n", d);
printf("%p : char e[*d]\n", e);
free(d);
return EXIT_SUCCESS;
}
最終輸出結果是
經過地址匹配對於 vla 可變數組, GCC是放在棧上的. 全部能夠預測, 當可變數組大小太大. 函數棧會直接崩潰.
若是你有想法, 那麼就去實現它, 多數簡單咱們仍是能獨立捉出來滴~~
通用套路
還有一種套路, 採用宏模板去實現, 簡單提一下這個思路. 看下面代碼
#ifdefined(__T)#define__f(type) sort_insert_##type#define__F(type) __f(type)staticvoid__F(__T) (__T a[],intlen,intcompare(const__T left,const __T key)) {
int i, j;
for(i =1; i < (int)len; ++i) {
__T key = a[j = i];
while(j >0&& compare(a[j -1], key) <0) {
a[j] = a[j -1];
--j;
}
a[j] = key;
}
}#endif
通常而言上面模板函數都會封裝在一個局部文件中使用的時候也很方便, 例以下面這樣
// 定義部分, 聲明和定義分離能夠本身搞#undef__T#define__T int#include "sort_insert.c"// 使用部分和普通函數無異sort_insert_int(a, LEN(a), _compare_2);
固然除了上面一種基於文件的函數模板. 還用一種純基於函數宏的函數模板實現.
#definesort_insert_definition(T) \staticvoidsort_insert_##T (T a[],intlen,intcompare(constT left,const T key)) { \
int i, j; \
for(i =1; i < len; ++i) { \
T key = a[j = i]; \
while(j >0&& compare(a[j -1], key) <0) { \
a[j] = a[j -1]; \
--j; \
} \
a[j] = key; \
} \
}
sort_insert_definition(int)
使用仍是同樣 sort_insert_int(a, LEN(a), _compare_2); 跑起來. 第一種函數模板, 在嵌入式用的多
第二種在實戰中用的多, 對於處理各類算法相關的代碼很廣泛. 到這裏應該能夠理解上面那些
C 封裝中一個小函數存在的套路
另外若是你想更好的提高你的編程能力,學好C語言C++編程!彎道超車,快人一步!筆者這裏或許能夠幫到你~
歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比本身琢磨更快哦!
編程學習: