【C語言】qsort的秘密

一,本文目標?

qsort函數可以對任意類型數據甚至是結構體內部的數據按照你想要的規則排序,它的功能很強大,可是為什么呢?

我將通過模擬實現qsort函數來讓你對這整個過程有一個清晰的深刻的理解。


二,qsort函數原型

void qsort (void* base,//要排序的對象的第一個元素的首地址size_t num, //對象的個數size_t size,//每一個對象的大小 Size in bytesint (*compar)(const void*,const void*));//Pointer to a function that compares two elements.(并且這個函數要自己寫)

????????qsort函數底層通過快速排序進行,但是這并不是我們感興趣的點,我想要知道qsort為什么可以對任意類型數據進行排序,與它用什么排序算法排序沒有關系,所以,我們用相對簡單的冒泡排序來代替快速排序的算法,把冒泡排序賦予可以對任意類型數據進行排序的強大功能。


三,冒泡排序——大數沉底,小數上浮

?對于冒泡排序,其基本思想是大數沉底,小數上浮;

這里直接給出源碼:

void Bubble_sort(int arr[], int size)
{int j,i;for (i = 0; i < size-1;i++)//排序趟數等于元素個數-1{int f = 0;for (j = 0; j < size - 1 - i; j++)//每一趟都有一個元素復位,需要排序的次數每次-1{if ( arr[j] > arr[j+1] ){int tem = arr[j];arr[j] = arr[j+1];arr[j+1] = tem;f = 1;}}if (f == 0)	{break;}}

3.1相對于qsort,冒泡排序的局限性

????????只能排序整形數據?

四,兩個問題:

4.1不定類型比較問題

? ? ? ? 1.對于if內部的判斷,雖然字符型可以用 >,<,= 比較,但是對于字符串類型,無法通過常規方法比較;

4.2不定類型交換問題

? ? ? ? 2.對于交換部分,由于不同元素的類型不同,占用的內存空間也不同,如何判斷傳入數據的類型,并實現兩個數據的交換呢?


五,改造冒泡排序

我們將自己模擬實現的qsort函數稱my_qsort,實現如下:


void my_qsort(void* base,size_t sz,size_t width,int (*cmp)(const void* p1,const void* p2))//cmp 是函數指針,在my_sort中被多次調用
{//它指向的函數是int_cmp,int_cmp就是回調函數int i = 0;for(i = 0;i < sz - 1;i++)//趟數不變{int j = 0;for(j = 0;j < sz - i - 1;j++)//每一趟進行的比較數不變{if(cmp((char*)base + j * width,(char*)base + (j + 1) * width) > 0 )//判斷要改變{Swap((char*)base + j * width,(char*)base + (j + 1) * width,width);}}}
}

5.1不同類型比較

我們定義一個cmp函數來實現比較:

5.1.1cmp實參

我們傳入排序的數組的首元素地址base,將base強制類型轉化為 char* 類型,這樣base與整數的運算就只會跨過這個整數個字節;

如果再知道每個元素的大小(長度),那么我們就可以精確的訪問到每個元素了;


怎么理解呢??

?e.g.1:對于int

?圖中的base指針的位置是?j == 1的位置

?e.g.2:對于char

?

?圖中的base指針的位置是 j?== 5 的位置?

5.1.2cmp形參

int int_cmp(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}

由于比較的對象是整型,所以定義一個比較整形的函數,void* 類型不能直接解引用,所以將p1,p2強制類型轉化,將兩數相減返回。

5.2不定類型交換問題

定義交換函數Swap?

void Swap(char* buf1,char* buf2,int width)//按字節逐個交換
{for(int i = 0;i < width;i++){char tem = *buf1;*buf1 = *buf2;*buf2 = tem;buf1++;//如果是整型,則要遍歷四個字節buf2++;}
}

這時候,我們就知道定義width的意義了,對于一個數據類型,我們雖然不知道它的類型,但是我們可以根據它的長度,一個一個字節地交換數據。


整體代碼運行

對于所有類型,我們的冒泡排序都可以排序了,它的作用與庫函數qsort一致,仍然需要我們自己寫cmp函數:;

對int型數據的排序:

#include<stdio.h>
#include<string.h>
int int_cmp(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1,char* buf2,int width)//按字節逐個交換
{for(int i = 0;i < width;i++){char tem = *buf1;*buf1 = *buf2;*buf2 = tem;buf1++;//如果是整型,則要遍歷四個字節buf2++;}
}void my_qsort(void* base,size_t sz,size_t width,int (*cmp)(const void* p1,const void* p2))//cmp 是函數指針,在my_sort中被多次調用
{//它指向的函數是int_cmp,int_cmp就是回調函數int i = 0;for(i = 0;i < sz - 1;i++)//趟數不變{int j = 0;for(j = 0;j < sz - i - 1;j++)//每一趟進行的比較數不變{if(cmp((char*)base + j * width,(char*)base + (j + 1) * width) > 0 )//判斷要改變{Swap((char*)base + j * width,(char*)base + (j + 1) * width,width);}}}
}void test1(void)
{int arr[] = {2,5,8,9,6,3,1,4,7,0};int sz = sizeof(arr)/sizeof(arr[0]);my_qsort(arr,sz,sizeof(arr[0]),int_cmp);for(int i = 0;i < sz;i++){printf("%d ",arr[i]);}
}int main()
{test1();return 0;
}

對于結構體類型,也可根據結構體內部某一元素的特征排序:

結構體類型

對結構體內的int型數據排序:


struct stu
{char name[20];int age;
};int struct_cmp_by_age(const void* p1,const void* p2)
{return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}void test2(void)
{struct stu arr[] = {{"zhangsan",18},{"lisi",25},{"wangwu",30},{"xiaoming",40}};int sz = sizeof(arr)/sizeof(arr[0]);my_qsort(arr,sz,sizeof(arr[0]),struct_cmp_by_age);for(int i = 0;i < sz;i++){printf("%s %d\n",arr[i].name,arr[i].age);}
}int main()
{test2();return 0;
}

對結構體內的char型數據排序:


struct stu
{char name[20];int age;
};int struct_cmp_by_name(const void* p1,const void* p2)
{return strcmp(((struct stu*)p1)->name,((struct stu*)p2)->name);
}void test3(void)
{struct stu arr[] = {{"zhangsan",18},{"lisi",25},{"wangwu",30},{"xiaoming",40}};int sz = sizeof(arr)/sizeof(arr[0]);my_qsort(arr,sz,sizeof(arr[0]),struct_cmp_by_name);for(int i = 0;i < sz;i++){printf("%s %d\n",arr[i].name,arr[i].age);}
}int main()
{//test1();//test2();test3();return 0;
}

1.對字符串的比較用到<string.h>中的strcmp函數,而它的返回值正好符合qsort函數第四個參數:函數的要求?

?

?

第一個字符串大于第二個,strcmp返回大于0的數,對應qsort函數要求第四個函數的返回值大于0,表示第一個參數大一第二個。?


本文回顧?

目錄

一,本文目標?

二,qsort函數原型

三,冒泡排序——大數沉底,小數上浮

3.1相對于qsort,冒泡排序的局限性

四,兩個問題:

4.1不定類型比較問題

4.2不定類型交換問題

五,改造冒泡排序

5.1不同類型比較

5.1.1cmp實參

5.1.2cmp形參

5.2不定類型交換問題

整體代碼運行

對int型數據的排序:

結構體類型

對結構體內的int型數據排序:

對結構體內的char型數據排序:


完~

未經作者同意禁止轉載

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167533.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167533.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167533.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode刷題詳解一

算法題常用API std::accumulate 函數原型&#xff1a; template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init );一般求和的&#xff0c;代碼如下&#xff1a; int sum accumulate(vec.begin() , vec.end() , 0);詳細用法參考 lo…

【python海洋專題四十七】風速的風羽圖

【python海洋專題四十七】風速的風羽圖 圖片 往期推薦 圖片 【python海洋專題一】查看數據nc文件的屬性并輸出屬性到txt文件 【python海洋專題二】讀取水深nc文件并水深地形圖 【python海洋專題三】圖像修飾之畫布和坐標軸 【Python海洋專題四】之水深地圖圖像修飾 【Pyth…

記一次linux操作系統實驗

前言 最近完成了一個需要修改和編譯linux內核源碼的操作系統實驗&#xff0c;個人感覺這個實驗還是比較有意思的。這次實驗總共耗時4天&#xff0c;從對linux實現零基礎&#xff0c;通過查閱資料和不斷嘗試&#xff0c;直到完成實驗目標&#xff0c;在這過程中確實也收獲頗豐&…

pytorch模型優化簡介,未完結版

如有幫助&#xff0c;點贊收藏關注&#xff01; 如需轉載&#xff0c;請注明出處&#xff01; 今天來介紹torch模型中的優化器 優化是指在每個訓練步驟中調整模型參數以減少模型誤差的過程。 優化算法定義如何執行這個過程 所有優化邏輯都封裝在優化器對象中。在這里&#xf…

【黑馬甄選離線數倉day04_維度域開發】

1. 維度主題表數據導出 1.1 PostgreSQL介紹 PostgreSQL 是一個功能強大的開源對象關系數據庫系統&#xff0c;它使用和擴展了 SQL 語言&#xff0c;并結合了許多安全存儲和擴展最復雜數據工作負載的功能。 官方網址&#xff1a;PostgreSQL: The worlds most advanced open s…

音視頻項目——RTSP服務器解析(1)

介紹 利用線程池&#xff0c;實現 RTSP 服務器的高并發請求處理。 RTSP 是音視頻的控制視頻的協議&#xff0c;如果您還不了解&#xff0c;可以看看之前我解析 RTSP 協議的文章。音視頻協議解析(RTP/RTCP/RTSP/RTMP)——RTSP解析-CSDN博客 解析 我們先來看 RTP 的實現。RTP 是音…

Django框架之auth模塊

目錄 一、Auth模塊引入 二、創建超級用戶(管理員) 三、依賴于auth_user表完成登錄注冊功能 【1】基礎登陸 【2】保存用戶狀態 【3】登錄后跳轉 (1) 登錄后才能訪問頁面 -- 局部配置 (2) 登錄后才能訪問頁面 -- 全局配置 (3) 小結 三、修改密碼 四、注銷 五、注冊…

Springboot將多個圖片導出成zip壓縮包

Springboot將多個圖片導出成zip壓縮包 將多個圖片導出成zip壓縮包 /*** 判斷時間差是否超過6小時* param startTime 開始時間* param endTime 結束時間* return*/public static boolean isWithin6Hours(String startTime, String endTime) {// 定義日期時間格式DateTimeFormatt…

【數據結構】—搜索二叉樹(C++實現,超詳細!)

&#x1f3ac;慕斯主頁&#xff1a;修仙—別有洞天 ??今日夜電波&#xff1a;消えてしまいそうです—真夜中 1:15━━━━━━?&#x1f49f;──────── 4:18 &#x1f504; ?? ? ??…

函數計算的新征程:使用 Laf 構建 AI 知識庫

Laf 已成功上架 Sealos 模板市場&#xff0c;可通過 Laf 應用模板來一鍵部署&#xff01; 這意味著 Laf 在私有化部署上的擴展性得到了極大的提升。 Sealos 作為一個功能強大的云操作系統&#xff0c;能夠秒級創建多種高可用數據庫&#xff0c;如 MySQL、PostgreSQL、MongoDB …

js實現獲取原生form表單的數據序列化表單以及將數組轉化為一個對象obj,將數組中的內容作為對象的key轉化為對象,對應的值轉換為對象對應的值

1.需求場景 哈嘍 大家好啊&#xff0c;今天遇到一個場景&#xff0c; js實現獲取原生form表單的數據序列化表單以及將數組轉化為一個對象obj&#xff0c;將數組中的內容作為對象的key轉化為對象&#xff0c;對應的值轉換為對象對應的值 數組對象中某個屬性的值&#xff0c;轉…

元宇宙現已開放!

在 2023 年 11 月 3 日 The Sandbox 首個全球創作者日上&#xff0c;The Sandbox 聯合創始人 Arthur Madrid 和 Sebastien Borget 宣布元宇宙已開放&#xff0c;已創作完整體驗的 LAND 持有者可以自行將體驗發布至 The Sandbox 地圖上。 精選速覽 LAND 持有者&#xff1a;如果…

在JVM中 判定哪些對象是垃圾?

目錄 垃圾的條件 1、引用計數法 2、可達性分析 3、強引用 4、軟引用 5、弱引用 6、虛引用 判斷垃圾的條件 在Java虛擬機&#xff08;JVM&#xff09;中&#xff0c;垃圾收集器負責管理內存&#xff0c;其中的垃圾收集算法用于確定哪些對象是垃圾&#xff0c;可以被回收…

VBA即用型代碼手冊之工作薄的關閉保存及創建

我給VBA下的定義&#xff1a;VBA是個人小型自動化處理的有效工具。可以大大提高自己的勞動效率&#xff0c;而且可以提高數據的準確性。我這里專注VBA,將我多年的經驗匯集在VBA系列九套教程中。 作為我的學員要利用我的積木編程思想&#xff0c;積木編程最重要的是積木如何搭建…

[Latex] Riemann 問題中的激波,接觸間斷,膨脹波的 Tikz 繪圖

Latex 代碼 \begin{figure}\begin{subfigure}[b]{0.32\textwidth}\centering\resizebox{\linewidth}{!}{\begin{tikzpicture}\coordinate (o) at (0,0);\coordinate (Si) at (2.5,2.5);\coordinate (x) at (1,0);\draw[->] (0,0) -- (3,0) node[right] {$x$};\draw[->] …

ArkTS-自定義組件學習

文章目錄 創建自定義組件頁面和自定義組件生命周期自定義組件和頁面的區別頁面生命周期(即被Entry修飾的組件)組件生命周期(即被Component修飾的組件) Builder裝飾器&#xff1a;自定義構建函數按引用傳遞參數按值傳遞參數 BuilderParam裝飾器&#xff1a;引用Builder函數 這個…

Python 將列表拼接為一個字符串,Python join

目錄 join方法的源碼&#xff1a; 列表數據為字符串 列表數據為數字 三引號也可以使用join join方法的源碼&#xff1a; def join(self, abNone, pqNone, rsNone): # real signature unknown; restored from __doc__"""Concatenate any number of strings.T…

harmonyos應用開發者高級認證考試部分答案

1只要使用端云一體化的云端資源就需要支付費用&#xff08;錯&#xff09; 2所有使用Component修飾的自定義組件都支持onPageShow&#xff0c;onBackPress和onPageHide生命周期函數。&#xff08;錯&#xff09; 3 HarmonyOS應用可以兼容OpenHarmony生態&#xff08;對&#…

一文讀懂如何安全地存儲密碼

目錄 引言 明文存儲 基本哈希存儲 加鹽哈希存儲 適應性哈希算法 密碼加密存儲 小結 引言 密碼是最常用的身份驗證手段&#xff0c;既簡單又高效。密碼安全是網絡安全的基石&#xff0c;對保護個人和組織信息的安全具有根本性的作用。然而有關密碼泄漏的安全問題一再發生…

生物動力葡萄酒和有機葡萄酒一樣嗎?

農業維持了數十萬年的文明&#xff0c;但當人類以錯誤的方式過多干預&#xff0c;過于專注于制造和操縱產品時&#xff0c;農業往往會失敗。如果我們的目標是獲得最高質量的收成&#xff0c;并長期堅持我們的做法&#xff0c;我們就必須與土地打交道。 當我們開始尋找生物動力…