網站首頁 編程語言 正文
一、qsort函數簡介
qsort函數是由C語言提供的標準庫函數, 它的實現思想是快速排序,qosrt函數的頭文件是stdlib.h。
qsort函數可以排序任意類型的數組。它的返回類型是void,參數是(void* base,size_t num,size_t size,int(*compar)(const void* e1,const void* e2))
。
接下來對它的參數進行分析:
參數void* base中base是void*類型的指針,base指向待排序數組的第一個元素的地址,也就是指向數組的起始位置。
參數size_t num中size_t表示的是無符號整型,num表示的是待排序數組中總的元素個數。
參數size_t size中size表示的是待排序數組中每個元素占幾個字節。
參數int (*compar)(const void* e1, const void* e2)是函數指針,int表示指向函數的返回類型是int類型,compar表示的是函數指針變量,指向函數的地址,被指向的函數用于比較兩個元素的大小。
在參數int (*compar)(const void* e1, const void* e2)中,函數指針變量compar指向的函數返回類型是int,返回值的大小可以分為三種情況:
返回值 | 條件 |
---|---|
>0 | e1>e2 |
<0 | e1<e2 |
=0 | e1=e2 |
二、qsort函數的使用
1.整型數組排序
#include <stdio.h> #include <stdlib.h> int cmp_int(const void* e1, const void* e2) { return *((int*)e1) - *((int*)e2);//默認是升序,將return中e1和e2的位置交換可以使其降序 //無法對void*類型的指針進行具體操作,因此要將其強制類型轉換為int*,使其能夠在解引用時訪問到4個字節 } int main() { int i = 0; int arr[] = { 7,8,9,4,5,6,1,2,3,10 }; int sz = sizeof(arr) / sizeof(arr[0]);//計算整型數組中有多少個元素 qsort(arr, sz, sizeof(int), cmp_int);//sizeof(int)是用來計算int類型的數據所占字節數 for (i = 0; i < sz; i++) { printf("%d ", arr[i]);//輸出為1 2 3 4 5 6 7 8 9 10 } return 0; }
注意:當函數的形參為void*類型,要對其進行具體操作時,應該將其強制類型轉換為所需的指針類型
2.字符串排序
#include <stdio.h> #include <stdlib.h> int cmp_char(const void* e1, const void* e2)//字符串排序 { return strcmp((char*)e1, (char*)e2);//比較字符大小用strcmp } int main() { char arr[] = "badecf"; int i = 0; //int sz = sizeof(arr) / sizeof(arr[0]);//sizeof求字符串長度會將\0算進去,也就是實際計算出來的會比數組中的多1。 int sz = strlen(arr);//strlen是用來計算字符串長度的,且只能用來計算字符串的長度。 qsort(arr,sz , sizeof(char), cmp_char); printf("%s\n", arr);//abcdef return 0; }
3.字符串長度排序
#include <stdio.h> #include <stdlib.h> int cmp_char_strlen(const void* e1, const void* e2)//比較字符串長度 { return strlen(*(char**)e1) - strlen(*(char**)e2);//先將e1和e2強制類型轉換成為char**類型,再解引用取出數組中字符串的地址,計算字符串長度 } int main() { //char* arr[] = {"abcdef" "abc","defs" }; //也可以通過下面的方式來寫指針數組,下面的4行和上面的這一行作用一樣 char* arr1 = "abc"; char* arr2 = "abcd"; char* arr3 = "abcdef"; char* arr[] = { arr1,arr2,arr3 }; int i = 0; qsort(arr, 3, sizeof(char*), cmp_char_strlen); for (i = 0; i < 3; i++) { printf("%s\n", arr[i]);//輸出結果為 abc defs abcdef } return 0; }
4.浮點型數組排序
#include <stdio.h> #include <stdlib.h> int cmp_float(const void* e1, const void* e2)//浮點型數組排序 { //return (int)(*(float*)e1 - *(float*)e2);//可能會出錯,如12.002和12.001比較之后再強制類型轉換為int類型后,結果為0 if (*(float*)e1 - *(float*)e2 > 0.000000) { return 1;//當e1>e2時,返回大于0的數 } if (*(float*)e1 - *(float*)e2 < 0.000000) { return -1;//當e1<e2時,返回小于0的數 } else return 0;//當e1和e2相等時,返回等于0的數 } int main() { float arr[3] = { 12.01f,12.03f,12.09f }; int sz = sizeof(arr) / sizeof(arr[0]);//計算數組長度 qsort(arr, sz, sizeof(float), cmp_float); int i = 0; for (i = 0; i < sz; i++) { printf("%f ", arr[i]);//輸出結果為12.010000 12.030000 12.090000 } return 0; }
5.結構體類型排序
#include <stdio.h> #include <stdlib.h> struct stu { char name[20]; int age; }; int cmp_s_age(const void* e1, const void* e2)//比較結構體中int類型 { return ((struct stu*)e1)->age - ((struct stu*)e2)->age; } int cmp_s_name(const void* e1, const void* e2)//比較結構體中char類型的數組 { return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name); } int main() { struct stu s[] = { {"zhangsan",21} ,{"lisi",20},{"wangwu",52}}; int i = 0; int sz = sizeof(s) / sizeof(s[0]); for (i = 0; i < sz; i++) { printf("%s %d\n", s[i].name, s[i].age); } qsort(s, sz, sizeof(struct stu), cmp_s_age);//比較年齡,即比較int類型 //qsort(s, sz, sizeof(struct stu), cmp_s_name);//比較姓名,即比較char類型的數組 printf("\n"); for (i = 0; i < sz; i++) { printf("%s %d\n", s[i].name, s[i].age);//輸出為年齡按照升序排列,如果比較姓名,則按照姓名的首字符的ASCII值按照升序排列 } return 0; }
三、冒泡排序實現qsort函數的功能
1.冒泡排序簡介
冒泡排序是通過對兩個相鄰元素進行比較,如果不符合條件就相互交換位置,并與后面相鄰的元素再次比較,直至滿足條件為止。
對于冒泡排序,如果它有n個元素,它將進行n-1次的循環。冒泡排序的缺點是只能對整型數組進行排序。
我們通過對整型數組排序進一步了解冒泡排序
//用冒泡排序對整型數組進行排序 #include <stdio.h> int main() { int i = 0; int j = 0; int arr[] = { 7,8,9,4,5,6,1,2,3,10 }; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz-1; i++)//總共循環sz-1次 { int flag = 1;//標記,假設數組是有序的 for (j = 0; j < sz - 1 - i; j++)//第一個元素需要和剩余的sz-1個元素比較,第二個元素需要和sz-1-1個元素比較……所以每次循環需要比較的次數為sz-1-i { if (arr[j] < arr[j + 1])//從大到小排列 { int tmp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = tmp; flag = 0;//倘若發生交換說明數組是無序的 } } if(flag == 1) { break;//如果沒發生一次交換說明數組已經是符合要求的有序數組 } } for (i = 0; i < sz; i++) { printf("%d ", arr[i]);//輸出結果為 10 9 8 7 6 5 4 3 2 1 } return 0; }
2.冒泡排序實現qsort函數功能
對冒泡排序進行qsort化時,要參照qsort函數的參數,盡量做到參數一致。
void qsort_bubble(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
void* base表示對應數組元素的起始位置。
int sz表示數組中元素總個數。
int width表示數組中每個元素所占字節數。
int(*cmp)(const void* e1, const void* e2)是函數指針,指向比較兩個元素大小的函數。
設計的冒泡排序qsort化函數qsort_bubble與庫函數qsort的參數意義相同。在qsort_bubble和qsort參數中函數指針指向的用于比較數組中兩個元素大小的函數不用發生改變,可以直接引用。
利用冒泡排序思想實現qsort函數功能并對結構體排序。
#include <stdio.h> struct stu { char name[20]; int age; }; int cmp_s_age(const void* e1, const void* e2)//比較結構體中整型 { return ((struct stu*)e1)->age - ((struct stu*)e2)->age; } int cmp_s_name(const void* e1, const void* e2)//比較結構體中整型 { return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name); } void Swap(char* buf1, char* buf2, int width) { int i = 0; for (i = 0; i < width; i++)//一個字節一個字節的交換 { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void qsort_bubble(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2)) { int i = 0; for (i = 0; i < sz - 1; i++) { int j = 0; for (j = 0; j < sz - 1 - i; j++) { if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0) //強制轉換成char*類型的指針,進行交換時一個字節一個字節的交換,+width,向后走對應的字節 { Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);//滿足條件進行交換 } } } } int main() { struct stu s[] = { {"zhangsan",21} ,{"lisi",20},{"wangwu",52}}; int i = 0; int sz = sizeof(s) / sizeof(s[0]); //printf("%d", sz); for (i = 0; i < sz; i++) { printf("%s %d\n", s[i].name, s[i].age); } qsort_bubble(s, sz, sizeof(struct stu), cmp_s_age);//比較年齡,即比較int類型 //qsort_bubble(s, sz, sizeof(struct stu), cmp_s_name);//比較姓名,即比較char類型的數組 printf("\n"); for (i = 0; i < sz; i++) { printf("%s %d\n", s[i].name, s[i].age); } return 0; }
原文鏈接:https://blog.csdn.net/weixin_53943591/article/details/127168902
相關推薦
- 2022-06-06 typescript類型別名、限制值的大小
- 2022-11-20 TS?中的類型推斷與放寬實例詳解_其它
- 2022-08-06 WinForm項目中添加幫助文檔功能_C#教程
- 2022-07-14 C語言深入探索之單鏈表與typedef的用法_C 語言
- 2023-10-17 git更換遠端地址
- 2023-07-07 spring security權限路由匹配restful格式的詳情id設計
- 2022-03-25 centos系統安裝Kubernetes集群步驟_Linux
- 2022-04-08 Python實現自定義異常實例_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支