国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

體現(xiàn)網(wǎng)站特色全球熱門網(wǎng)站排名

體現(xiàn)網(wǎng)站特色,全球熱門網(wǎng)站排名,多用戶小程序系統(tǒng)開發(fā),wordpress 修改gravatar方法🌈write in front :🔍個人主頁 : 啊森要自信的主頁 ??真正相信奇跡的家伙,本身和奇跡一樣了不起啊! 歡迎大家關注🔍點贊👍收藏??留言📝>希望看完我的文章對你有小小的幫助&am…
  🌈write in front :

🔍個人主頁 : @啊森要自信的主頁

??真正相信奇跡的家伙,本身和奇跡一樣了不起啊!

歡迎大家關注🔍點贊👍收藏??留言📝>希望看完我的文章對你有小小的幫助,如有錯誤,可以指出,讓我們一起探討學習交流,一起加油鴨。 請?zhí)砑訄D片描述

文章目錄

  • 前言
  • 一、轉(zhuǎn)移表
  • 二、回調(diào)函數(shù)是什么?
  • 三、qsort函數(shù)細解
    • 3.1 類比冒泡排序?
    • 3.2 qosrt函數(shù)超詳解
    • 3.2.1qsort函數(shù)排序整型數(shù)據(jù)
    • 3.2.2 使?qsort排序結構數(shù)據(jù)
  • 四、 qsort函數(shù)的模擬實現(xiàn)
    • 4.1 模擬qsort整形數(shù)據(jù)
    • 4.2 模擬`qsort`排序結構數(shù)據(jù)
  • 總結


前言

本小節(jié),我們將繼續(xù)學習C語言轉(zhuǎn)移表,什么是回調(diào)函數(shù),回調(diào)函數(shù)又是什么?qsort函數(shù)怎么使用,怎么理解處理,要注意的細節(jié),當然qsort使用舉例,最后我們進行qsort函數(shù)的模擬實現(xiàn)!文章干貨滿滿,走起!


一、轉(zhuǎn)移表

C語言轉(zhuǎn)移表是指根據(jù)一定條件,實現(xiàn)程序執(zhí)行流程的跳轉(zhuǎn)或轉(zhuǎn)移的機制。

具體來說,C語言中實現(xiàn)轉(zhuǎn)移表的主要方式有:

  1. goto語句:
    goto語句可以實現(xiàn)無條件跳轉(zhuǎn),直接跳轉(zhuǎn)到指定標簽所在的代碼塊
goto 標簽名; 

例如:

goto label;
  1. switch語句:
    switch語句根據(jù)表達式的值,選擇性地執(zhí)行一個代碼塊。它實現(xiàn)了有條件跳轉(zhuǎn)。
switch(表達式)
{case 常數(shù)表達式1://語句break;case 常數(shù)表達式2:  //語句break;//其他casedefault://語句
}
  1. continue語句:
    continue 用于跳過循環(huán)體剩余部分,直接跳轉(zhuǎn)到循環(huán)條件判斷語句。

例如:

for(i=0;i<10;i++)
{if(i==5)continue;printf("%d",i);
}
  1. break語句:
    break 用于跳出整個循環(huán)或switch語句。

例如:

for(i=0;i<10;i++)
{if(i==5)break;printf("%d",i);
} 
  1. return語句:
    return 用于從函數(shù)中返回。

例如:

int func()
{return 0;
}
  1. 拓展:longjmp()/setjmp():

setjmp()longjmp()是C語言中的兩個非常重要的函數(shù),它們可以實現(xiàn)非局部跳轉(zhuǎn)的功能。

  • setjmp()函數(shù)聲明如下:
  int setjmp(jmp_buf env);
  • jmp_buf是可以保存環(huán)境信息的結構體。

  • setjmp()會將當前函數(shù)的執(zhí)行環(huán)境信息保存到env中,并返回0。

  • 然后程序可以正常執(zhí)行。

  • 當需要跳轉(zhuǎn)時,調(diào)用longjmp(env, val);

    longjmp()函數(shù)聲明如下:

 void longjmp(jmp_buf env, int val);
  • longjmp()第一個參數(shù)就是setjmp()保存的env。

  • 它會將程序跳轉(zhuǎn)回setjmp()后面要執(zhí)行的代碼。

  • 但此時setjmp()會返回longjmp()第二個參數(shù)val,而不是0
    jmp_buf env是setjmp和longjmp函數(shù)用來保存環(huán)境信息的結構體變量。

jmp_buf是一個預定義的數(shù)據(jù)類型,它用來描述一個環(huán)境的狀態(tài)。

  • env是一個jmp_buf類型的變量。
  • 當調(diào)用setjmp(env)時,setjmp函數(shù)會將當前函數(shù)調(diào)用棧(包括函數(shù)參數(shù)、局部變量等環(huán)境信息)保存到env這個結構體變量中。
  • 之后程序可以正常執(zhí)行。
  • 當需要非局部跳轉(zhuǎn)時,調(diào)用longjmp(env, val)。longjmp函數(shù)第一個參數(shù)就是這個env。
  • longjmp通過env這個結構體,可以恢復到setjmp函數(shù)保存環(huán)境時的狀態(tài)。實現(xiàn)一個“跳回”的效果。

小總結:

  • jmp_buf是一個結構體類型,它可以保存一個函數(shù)環(huán)境的狀態(tài)信息。
  • env是一個此類型的變量,用于在setjmplongjmp之間傳遞環(huán)境信息。
  • setjmp函數(shù)把當前環(huán)境信息保存到env中。
  • longjmp函數(shù)通過env這個結構體,實現(xiàn)恢復到setjmp時的環(huán)境狀態(tài),從而實現(xiàn)非局部跳轉(zhuǎn)。

哎!當然你可以把env可以看作是一個“傳送令牌”,只要通過longjmp把令牌改了,他就重新傳送到setjmp,然后繼續(xù)執(zhí)行,它連接setjmp和longjmp,使得longjmp能找到正確的環(huán)境信息進行跳轉(zhuǎn)。

所以通過setjmp()/longjmp()就實現(xiàn)了一個非局部跳轉(zhuǎn):程序似乎"跳回"到setjmp()后面要執(zhí)行的代碼,但實際上環(huán)境已經(jīng)發(fā)生了變化。這在異常處理等場景中很有用。
工作原理是:

  1. setjmp()函數(shù)會保存當前函數(shù)調(diào)用棧(包括函數(shù)參數(shù)和局部變量等信息)的環(huán)境,并返回0。

  2. 之后程序可以正常執(zhí)行。

  3. 當需要非局部跳轉(zhuǎn)時,調(diào)用longjmp(),并將在setjmp()保存的環(huán)境作為參數(shù)傳入。

  4. 這個時候程序就會跳轉(zhuǎn)回setjmp()保存的環(huán)境,仿佛從setjmp()后面繼續(xù)執(zhí)行。但此時setjmp()會返回非0值。

舉個例子

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <setjmp.h>jmp_buf env; //jmp_buf是一個預定義的數(shù)據(jù)類型,它用來描述一個環(huán)境的狀態(tài)。//env是一個jmp_buf類型的變量。void func()
{//設置跳轉(zhuǎn)點int ret = setjmp(env);if (0 == ret){//正常流程printf("In func()\n");//觸發(fā)跳轉(zhuǎn)longjmp(env, 1);}else{//跳轉(zhuǎn)后流程printf("Jumped back to func()\n");}
}int main()
{func();return 0;
}

在這里插入圖片描述

程序執(zhí)行流程:

  1. 主函數(shù)調(diào)用func()函數(shù)。
  2. func()內(nèi)首先調(diào)用setjmp()設置跳轉(zhuǎn)點env。由于setjmp()第一次調(diào)用會返回0,所以進入if塊。
  3. 打印"In func()"信息。
  4. 調(diào)用longjmp(),觸發(fā)非局部跳轉(zhuǎn)。
  5. 程序跳轉(zhuǎn)回setjmp()設置的環(huán)境env,此時setjmp()返回1。
  6. 執(zhí)行else塊內(nèi)的代碼,打印"Jumped back to func()"。
  7. func()返回,主函數(shù)結束。

通過在函數(shù)內(nèi)使用setjmp()/longjmp(),實現(xiàn)了從函數(shù)內(nèi)非局部跳回函數(shù)外的功能。這與goto不同,可以實現(xiàn)跨函數(shù)的非順序跳轉(zhuǎn)。它常用于異常和錯誤處理等場景。

  1. C語言函數(shù)指針數(shù)組可以用來實現(xiàn)轉(zhuǎn)移表。

具體來說:

  • 定義一個函數(shù)指針數(shù)組,元素類型為函數(shù)指針。

  • 每個數(shù)組元素都指向一個具體的函數(shù)。

  • 根據(jù)條件調(diào)用數(shù)組對應元素所指向的函數(shù)。

這與傳統(tǒng)的switch語句實現(xiàn)轉(zhuǎn)移的效果是一致的。

一個簡單的示例:

// 函數(shù)定義
void func1() 
{printf("func1\n");
}void func2() 
{printf("func2\n"); 
}// 主函數(shù)
int main() 
{// 函數(shù)指針數(shù)組void (*funcs[])(void) = {func1, func2};int id = 1; // 條件值// 根據(jù)條件調(diào)用數(shù)組元素函數(shù)funcs[id]();return 0;
}

在這里插入圖片描述

這樣就實現(xiàn)了根據(jù)條件值動態(tài)調(diào)用不同函數(shù)的功能,相當于一個簡單的轉(zhuǎn)移表。

函數(shù)指針數(shù)組用于轉(zhuǎn)移表的優(yōu)點是:

  • 更靈活,可以在運行時動態(tài)添加/刪除函數(shù)
  • 擴展性好,支持條件復雜情況下的多路徑轉(zhuǎn)移
  • 與傳統(tǒng)switch語句相比代碼更簡潔清晰

所以總的來說,函數(shù)指針數(shù)組正是C語言實現(xiàn)轉(zhuǎn)移表的一個很好的選擇。它可以很好地替代switch語句實現(xiàn)更復雜的多路轉(zhuǎn)移邏輯。
通過這個你可能不太能看出哪里能很好的替代switch語句,讓我們來看一個典型的例子,實現(xiàn)一個計算器!!!

switch實現(xiàn)計算器:

主要實現(xiàn)計算器程序思路:

  1. 定義了四個運算函數(shù)add、sub、mul、div實現(xiàn)四則運算。

  2. main函數(shù)中:

  • 使用do while循環(huán)控制程序循環(huán)執(zhí)行。

  • 打印菜單讓用戶選擇運算類型。

  • 根據(jù)用戶選擇用switch case調(diào)用對應的運算函數(shù)。

  • 每次運算前輸入兩個操作數(shù),運算后打印結果。

  1. 選擇0退出循環(huán),退出程序。
#include <stdio.h>int add(int a, int b)//加法
{return a + b;
}int sub(int a, int b)//減法
{return a - b;
}int mul(int a, int b)//乘法
{return a * b;
}int div(int a, int b)//除法
{return a / b;
}int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf("****  1:add   2:sub   ***\n");printf("****  3:mul   4:div   ***\n");printf("****  0:exit   ....   ***\n");printf("*************************\n");printf("請選擇:");scanf("%d", &input);switch (input)//選擇{case 1:printf("輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("選擇錯誤,請重新選擇\n");break;}} while (input);return 0;
}

在這里插入圖片描述

實現(xiàn)是實現(xiàn)了,但是case里面的每個代碼塊除了ret = (?)(x,y);有點不同,其他都很相似,這么多代碼重復寫,會造成代碼的冗余,如果我們又繼續(xù)給用戶增加功能,比如&,^,>>等等,然后一個功能我們就加一個case,case多了,代碼重復的也多咋改變呢?

不著急,我們不是學習了函數(shù)指針數(shù)組嗎?

我們可以把函數(shù)的地址存儲在數(shù)組里面,然后通過指針訪問數(shù)組下標(0,1,2,3,4,5...),然后解引用找到我們要找到我們要實現(xiàn)函數(shù)的地址
然后給他傳參,再接收他的計算的返回值不就搞定了。
哈哈哈哈!!掌聲應該送給自己,說做就做!讓我們繼續(xù)往下走。
在這里插入圖片描述

函數(shù)指針數(shù)組實現(xiàn)計算器:

思路:

  1. 定義了4個函數(shù)Add、Sub、Mul、Div,用于四則運算。

  2. menu()函數(shù)打印菜單界面。

  3. 定義了一個函數(shù)指針數(shù)組pfArr,元素類型為int (*)(int, int),可以存儲這4個二元運算函數(shù)的地址。

  4. 在主函數(shù)中使用do-while循環(huán)不斷運行:

    • 調(diào)用menu()打印菜單

    • scanf輸入選擇

    • 根據(jù)選擇從pfArr數(shù)組中獲取對應函數(shù)的地址

    • 調(diào)用該函數(shù)進行運算

    • 打印結果

void menu()//封裝菜單
{printf("******************************\n");printf("****  1. add     2. sub   ****\n");printf("****  3. mul     4. div   ****\n");printf("****  0. exit             ****\n");printf("******************************\n");
}int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();//函數(shù)指針數(shù)組的方式解決一下//這里的函數(shù)指針數(shù)組,我們稱為轉(zhuǎn)移表// 為什么這里要加NULL,直接{add,sub,mul,div}不行嗎?如果真是可以的話,那我們觀察他的下標  0   1   2   3此時此刻,如果我們選擇1.add,那么(*p[1])取出的地址是sub,這不對呀,如果我們在前面加一個NULL{ NULL,add,sub,mul,div }下標為  0    1   2   3   4地址:*p[ 0 ] == 0,     *p[ 1 ] ==addint (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };//                           0     1    2    3    4printf("請選擇:");scanf("%d", &input);if (input == 0){printf("退出計算器\n");}else if (input >= 1 && input <= 4){										printf("請輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = pfArr[input](x, y);           //(*p[input])==add/sub/mul/div函數(shù)名,也就是函數(shù)的地址//(p[input])也可以,*號有無,都相當于函數(shù)名,也是函數(shù)地址// 也就是ret=(p[input])(x,y);printf("%d\n", ret);}else{printf("選擇錯誤,重新選擇\n");}} while (input);return 0;
}

解釋:
input輸入1, pfArr[1]取得Add的地址,然后通過Add函數(shù)的地址,執(zhí)行指令。(當然同理input輸入2,3,4也是同樣的步驟)。
如果要增加功能,那么可以int (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };增加相應的功能,然后增加相應功能的代碼塊!
比如,你想要增加位運算(&, |, ^)的功能:

  1. 增加位運算函數(shù):
int And(int x, int y) {return x & y;
}int Or(int x, int y) {return x | y;  
}int Xor(int x, int y) {return x ^ y;
}
  1. 修改菜單顯示:
void menu() {printf("******************************\n");printf("****  1. add     2. sub   ****\n"); printf("****  3. mul     4. div   ****\n");printf("****  5. &       6. |     ****\n");printf("****  7. ^              ****\n");  printf("****  0. exit             ****\n");printf("******************************\n");}
  1. 增加函數(shù)指針:
int (*pfArr[])(int, int) = {NULL, Add, Sub, Mul, Div, And, Or, Xor};
  1. 判斷函數(shù)選擇范圍:
if(input >= 1 && input <= 7) {ret = pfArr[input](x, y);}

這樣就增加了位運算的功能選擇了。

如果還需要其他運算,可以繼續(xù)增加對應的函數(shù)和菜單顯示即可。

但是,思考———>
int (*p[5])(int x, int y) = { NULL,add,sub,mul,div };那函數(shù)的add,sub,mul,div這些地址是不是也和一維數(shù)組一樣,存儲在函數(shù)指針數(shù)組里面,他們的地址是否是連續(xù)的呢?
解釋:

函數(shù)地址在函數(shù)指針數(shù)組中的存儲方式與一維數(shù)組類似,但有一點不同:

  • 函數(shù)指針數(shù)組pfArr中,add、sub等函數(shù)地址的存儲是連續(xù)的,就像一維數(shù)組元素一樣,如下標0,1,2,3,4這樣連續(xù)存儲后就可以訪問了。

  • 但是,函數(shù)本身的代碼可能不一定存儲在連續(xù)內(nèi)存地址中。

更準確地說:

  • 在函數(shù)指針數(shù)組pfArr中,add、sub等函數(shù)地址是以連續(xù)方式存儲的。

  • 而函數(shù)本身的代碼可能分散在不同代碼段(code section)中,地址不一定連續(xù)。

舉個例子:

假設add函數(shù)代碼在地址0x00001000,sub函數(shù)代碼在0x00002000,mul在0x00003000。

那么在函數(shù)指針數(shù)組pfArr中:

pfArr[1] 指向 add函數(shù)地址 0x00001000  
pfArr[2] 指向 sub函數(shù)地址 0x00002000
pfArr[3] 指向 mul函數(shù)地址 0x00003000

我們可以看到,pfArr[1]、pfArr[2]、pfArr[3]中的函數(shù)地址是以連續(xù)的方式存儲在數(shù)組中的。

但是函數(shù)本身的代碼地址0x00001000、0x00002000、0x00003000并不連續(xù)。

所以總結來說:

  • 函數(shù)指針數(shù)組pfArr中函數(shù)地址是連續(xù)存儲的
  • 但函數(shù)代碼本身不一定連續(xù)存儲在內(nèi)存中

在這里插入圖片描述

二、回調(diào)函數(shù)是什么?

C語言中的回調(diào)函數(shù)是指在函數(shù)調(diào)用的過程中,被另外一個函數(shù)作為參數(shù)傳遞并調(diào)用的函數(shù)。

回調(diào)函數(shù)的主要特征如下:

  1. 回調(diào)函數(shù)必須事先定義。

  2. 回調(diào)函數(shù)的地址作為參數(shù)傳遞給另一個函數(shù),這個函數(shù)稱為主函數(shù)。

  3. 主函數(shù)在適當?shù)臅r候,通過調(diào)用回調(diào)函數(shù)的地址來調(diào)用回調(diào)函數(shù)。

一個典型的回調(diào)函數(shù)使用場景例子:

// 回調(diào)函數(shù)定義
void callback_func(int value) 
{printf("value is %d\n", value);
}// 主函數(shù)定義
void main_func(void (*callback)(int)) 
{int num = 10;// 調(diào)用回調(diào)函數(shù)callback(num); 
}int main() 
{// 注冊回調(diào)函數(shù)main_func(callback_func);return 0;
}

注:回調(diào)函數(shù)的特點是函數(shù)的調(diào)用關系由使用者在運行時決定,而不是在編譯時就確定,這提供了更大的靈活性。

那可不可以使用回調(diào)函數(shù)實現(xiàn)計算器呢?

  1. 定義一個通用的計算函數(shù)calc,它接收一個函數(shù)指針作為參數(shù)。
  2. main函數(shù)中,根據(jù)用戶選擇直接調(diào)用calc函數(shù),并傳入相應的運算函數(shù)。
  3. 回調(diào)函數(shù)是Add、Sub、Mul、Div

在這里插入圖片描述

void menu()
{printf("******************************\n");printf("****  1. add     2. sub   ****\n");printf("****  3. mul     4. div   ****\n");printf("****  0. exit             ****\n");printf("******************************\n");
}int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}//calc功能強大了void calc(int (*pf)(int,int))
{int x = 0;int y = 0;int ret = 0;printf("請輸入兩個操作數(shù):");scanf("%d %d", &x, &y);ret = pf(x, y);printf("%d\n", ret);
}int main()
{int input = 0;do{menu();printf("請選擇:");scanf("%d", &input);switch (input){case 1:calc(Add);//完成計算	break;case 2:calc(Sub);break;case 3:calc(Mul);break;case 4:calc(Div);break;case 0:printf("退出計算器\n");break;default:printf("選擇錯誤,重新選擇\n");break;}} while (input);return 0;
}

在這里插入圖片描述

三、qsort函數(shù)細解

3.1 類比冒泡排序?

通過前面我們學過冒泡排序,qsort函數(shù)的排序讓我們類比一下:

void bubble_sort(int arr[], int sz)
{//趟數(shù)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 tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{//將一組整數(shù)排序為升序int arr[10] = { 3,1,5,2,4,6,8,7,0,9 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);bubble_sort(arr, sz);print_arr(arr, sz);return 0;
}

在這里插入圖片描述

在這里插入圖片描述

3.2 qosrt函數(shù)超詳解

庫函數(shù)的學習和查看?具很多,?如:
C/C++官?的鏈接:https://zh.cppreference.com/w/c/header
cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
qsort函數(shù)是C標準庫中用于對數(shù)組進行快速排序的函數(shù)。(注:qsort函數(shù)底層使用的排序算法就是快速排序。)

  • 函數(shù)原型:
void qsort(void* base,//base 指向了要排序的數(shù)組的第一個元素size_t num, //base指向的數(shù)組中的元素個數(shù)(待排序的數(shù)組的元素的個數(shù))size_t size,//base指向的數(shù)組中元素的大小(單位是字節(jié))int (*compar)(const void*p1, const void*p2)//函數(shù)指針 - 指針指向的函數(shù)是用來比較數(shù)組中的2個元素的);

.- [ ] 分析定義:

  • base指向要排序的數(shù)組首地址。

  • num表示數(shù)組元素個數(shù)。

  • size表示每個元素的大小,以字節(jié)為單位。

  • compar是比較函數(shù),它接收兩個void指針,返回值小于0表示第一個參數(shù)小于第二個參數(shù),等于0表示相等,大于0表示第一個參數(shù)大于第二個參數(shù)。

.- [ ] 特點:

  • qsort使用快速排序算法,時間復雜度為O(nlogn)。

  • 調(diào)用qsort時,需要提供一個比較函數(shù)compar來判斷兩個元素的大小關系。

  • 比較函數(shù)通過void指針間接訪問元素,避免與數(shù)據(jù)類型綁定,實現(xiàn)了最大程度的通用性。

  • qsort會在內(nèi)部調(diào)用比較函數(shù)多次對數(shù)組進行排序,這就是回調(diào)機制的實現(xiàn)。

  • qsortinplace排序,不需要額外的空間。

在這里插入圖片描述

在這里插入圖片描述

3.2.1qsort函數(shù)排序整型數(shù)據(jù)

#include <stdio.h>
#include <stdlib.h>void print_arr(int arr[], int sz)
{//打印函數(shù)int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}int cmp_int(const void* p1, const void* p2)
{//好比冒泡排序return *(int*)p1 - *(int*)p2;
}//測試qsort排序整型數(shù)據(jù)的
int main()
{int arr[10] = { 4,2,5,3,1,6,7,8,0,9 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);//打印前qsort(arr, sz, sizeof(arr[0]), cmp_int);//arr->數(shù)組首元素地址//sz->數(shù)組元素個數(shù)也可以這樣寫sz==sizeof(arr)/sizeof(arr[0])//sizeof(arr[0])->數(shù)組元素大小,這里字節(jié)大小為4//cmp_int比較函數(shù)print_arr(arr, sz);//打印后
}

在這里插入圖片描述

3.2.2 使?qsort排序結構數(shù)據(jù)

  1. 定義結構體類型
struct Stu
{char name[20];//名字int age;
};
  1. 定義比較函數(shù)
  • 怎么比較2個結構體數(shù)據(jù)? - 不能直接使用 > < ==比較
  • 可以按照名字比較
  • 可以按照年齡比較
//按照年齡比較
int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
}
  1. 聲明結構體數(shù)組和元素個數(shù)
void test2()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 38}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}

代碼實現(xiàn):

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>測試qsort函數(shù)排序結構體數(shù)據(jù)
struct Stu
{char name[20];//名字int age;
};int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
}
void print(struct Stu arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%s %d\n", arr[i].name, arr[i].age);}
}void test2()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 38}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);print(arr, sz);
}//	//兩個字符串不能使用> < ==
//	//而是使用庫函數(shù)strcmp - string compareint cmp_stu_by_name(const void* p1, const void* p2){return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);}void test3(){struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 38}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);print(arr, sz);}int main()
{test3();//姓名排序//test2();//年齡排序return 0;
}

運行test2()//年齡排序
在這里插入圖片描述

四、 qsort函數(shù)的模擬實現(xiàn)

4.1 模擬qsort整形數(shù)據(jù)

  1. 主函數(shù):

    • 定義int測試數(shù)據(jù)
    • 調(diào)用bubble排序
    • 打印結果驗證
#include <stdio.h>
int main()
{int arr[] = { 3, 1, 5, 8, 4, 2, 9, 6, 7, 0 };int i = 0;  //元素個數(shù)                   //元素大小bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);//數(shù)組首元素地址arr                                    //比較函數(shù)for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}
  1. bubble函數(shù):

    • 接收基地址、元素個數(shù)、元素大小、比較函數(shù)作為參數(shù)
    • 實現(xiàn)冒泡排序核心算法
    • 通過傳遞的比較函數(shù)int_cmp來決定排序順序
    • 使用_swap函數(shù)交換元素
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
  1. int_cmp函數(shù):

    • 定義一個int類型的數(shù)據(jù)比較函數(shù)
    • 通過減法實現(xiàn)兩個int*指針所指向的數(shù)據(jù)比較
    • 返回值大于0表示p1大于p2(升序),小于0表示p1小于p2(降序)
    • 實現(xiàn)了冒泡排序中的比較規(guī)則
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
  1. _swap函數(shù):

    • 定義泛型數(shù)據(jù)交換函數(shù)
    • 通過循環(huán)交換每個字節(jié)實現(xiàn)數(shù)據(jù)交換
    • 使用char*來交換,實現(xiàn)數(shù)據(jù)類型無關
void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}

在這里插入圖片描述

總結:
每個代碼塊實現(xiàn)的功能:

  • 主函數(shù): 測試驅(qū)動開發(fā)
  • bubble: 實現(xiàn)冒泡排序算法
  • int_cmp: 提供比較規(guī)則
  • _swap: 實現(xiàn)泛型數(shù)據(jù)交換

在這里插入圖片描述

4.2 模擬qsort排序結構數(shù)據(jù)

各個代碼塊分析如下:

  1. struct Stu定義結構體類型,包含姓名和年齡字段。
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>struct Stu
{char name[20];int age;
};
  1. Swap函數(shù)實現(xiàn)泛型數(shù)據(jù)交換,通過循環(huán)交換每個字節(jié)實現(xiàn)數(shù)據(jù)交換。
void Swap(char* buf1, char*buf2, size_t width)
{int i = 0;for (i = 0; i < width; i++) {char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
  1. bubble_sort2函數(shù)實現(xiàn)冒泡排序算法,和普通冒泡排序區(qū)別在于使用void*作為參數(shù),通過width實現(xiàn)對結構體進行排序。
void bubble_sort2(void* base, int sz, int width, int (*cmp)(const void* p1, const void* p2))
{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])if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){/*int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;*///交換Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}
  1. cmp_stu_by_age函數(shù)實現(xiàn)結構體比較規(guī)則,根據(jù)年齡字段進行比較。
int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
  1. test4函數(shù)定義測試數(shù)據(jù),調(diào)用bubble_sort2進行排序,打印結果驗證。
void test4()
{struct Stu arr[] = { {"zhangsan", 18},{"lisi", 35},{"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort2(arr, sz, sizeof(arr[0]), cmp_stu_by_age);//打印arr數(shù)組的內(nèi)容int i = 0;for (i = 0; i < sz; i++){printf("%s %d\n", arr[i].name, arr[i].age);}
}
  1. main函數(shù)調(diào)用test4函數(shù)進行測試。
int main()
{//模擬結構體按年齡排序test3();return 0;
}

在這里插入圖片描述

小總結

  • struct Stu定義了需要排序的數(shù)據(jù)類型
  • Swap函數(shù)實現(xiàn)數(shù)據(jù)交換
  • bubble_sort2實現(xiàn)泛型冒泡排序
  • cmp_stu_by_age定義了結構體比較規(guī)則
  • test4函數(shù)測試驅(qū)動開發(fā)

總結

一、轉(zhuǎn)移表
利用函數(shù)指針數(shù)組實現(xiàn)轉(zhuǎn)移表是動態(tài)規(guī)劃算法解決最優(yōu)子結構問題時使用的一種技術。它記錄了子問題的解,避免重復計算。

二、回調(diào)函數(shù)是什么?
回調(diào)函數(shù)是指在函數(shù)調(diào)用后,被當作參數(shù)傳遞給另一個函數(shù)的函數(shù)。調(diào)用方在需要時,會調(diào)用被調(diào)用方內(nèi)部的這個函數(shù)。

三、qsort函數(shù)細解

3.1 類比冒泡排序?
qsort函數(shù)實現(xiàn)的也是冒泡排序算法。不同之處在于:

  • qsort是通用排序函數(shù),可以對任意數(shù)據(jù)類型進行排序,而冒泡排序只能對數(shù)組進行排序;

  • qsort通過回調(diào)函數(shù)來指定元素的比較方式,而冒泡排序直接比較元素值;

  • qsort內(nèi)部實現(xiàn)采用快速排序思想,而不是純粹的冒泡排序。

3.2 qsort函數(shù)超詳解

qsort函數(shù)原型:

void qsort(void *base, size_t num, size_t size, int (*compar)(const void*, const void*));
  • base:待排序數(shù)組首地址
  • num:數(shù)組元素個數(shù)
  • size:每個元素大小
  • compar:比較函數(shù)回調(diào),返回值小于0時交換元素

3.2.1 qsort排序整型數(shù)據(jù)

直接傳入整型比較函數(shù)如int cmp(const void*, const void*)

3.2.2 使用qsort排序結構數(shù)據(jù)

定義結構體比較函數(shù),通過強制類型轉(zhuǎn)換比較結構體字段

四、qsort函數(shù)的模擬實現(xiàn)

4.1 模擬qsort整形排序
實現(xiàn)了一個簡單快速排序函數(shù),可以對整型數(shù)組排序。

4.2 模擬qsort結構體排序 同樣實現(xiàn)快速排序,但使用結構體比較函數(shù)作為回調(diào)。

感謝你的收看,如果文章有錯誤,可以指出,我不勝感激,讓我們一起學習交流,如果文章可以給你一個幫助,可以給博主點一個小小的贊😘
請?zhí)砑訄D片描述

http://aloenet.com.cn/news/39040.html

相關文章:

  • 建材網(wǎng)站建設 南寧sem代運營托管公司
  • 中山制作企業(yè)網(wǎng)站廣州網(wǎng)站制作服務
  • 公司介紹網(wǎng)站怎么做只要做好關鍵詞優(yōu)化
  • 商城小程序定制公司搜索引擎優(yōu)化的重要性
  • 收錄網(wǎng)站是怎么做的網(wǎng)絡營銷首先要
  • 織夢網(wǎng)站在css中怎樣做導航關鍵詞優(yōu)化公司靠譜推薦
  • 2019做網(wǎng)站需要營業(yè)執(zhí)照嗎2022最好的百度seo
  • 網(wǎng)頁源代碼搜索關鍵字如何seo推廣
  • php網(wǎng)站開發(fā)過程免費下載b站視頻軟件
  • 云南昆明做網(wǎng)站西安競價托管公司
  • 做網(wǎng)站需要什么基礎百度開發(fā)者平臺
  • 網(wǎng)站彈窗客服怎樣搭建自己的網(wǎng)站
  • 鹽城微網(wǎng)站建設廣州王牌seo
  • 開發(fā)一個網(wǎng)站的步驟推廣軟件賺錢的app
  • 廣州移動 網(wǎng)站設計如何在各大平臺推廣
  • 天津建設工程信息網(wǎng)如何注冊網(wǎng)站優(yōu)化推廣招聘
  • 網(wǎng)站搭建搜外友鏈
  • 如何開網(wǎng)店無貨源不需要投資河北seo技術
  • 在設計賺錢的網(wǎng)站有哪些做網(wǎng)站需要多少錢
  • 廣東省農(nóng)業(yè)農(nóng)村廳官方網(wǎng)站成都網(wǎng)站快速開發(fā)
  • 建站源碼程序惠州seo外包服務
  • 自己的網(wǎng)站怎么開培訓心得體會范文大全2000字
  • 外貿(mào)必看網(wǎng)站湖南百度seo
  • 做3d效果的網(wǎng)站亞馬遜關鍵詞排名提升
  • 松江品劃做網(wǎng)站云浮新增確診病例30例
  • 易企網(wǎng)站建設滁州網(wǎng)站seo
  • 系統(tǒng)優(yōu)化的方法知識點外貿(mào)建站優(yōu)化
  • 深圳網(wǎng)站建設加q479185700外貿(mào)網(wǎng)絡營銷推廣
  • 保障性租賃住房管理平臺優(yōu)化大師班級優(yōu)化大師
  • 網(wǎng)站建設與開發(fā)論文谷歌seo是什么意思