??前面的話??
大家好!對于排序有許多中方法,比如冒泡排序,選擇排序,希爾排序,插入排序,堆排序等等,但是怎樣能夠使用一個函式能夠對多個資料型別進行排序呢?無所不知的C語言開發者提供了一個qsort函式,它能夠對多種資料型別進行排序,實作各種資料型別的快速排序,這篇文章介紹qsort函式的使用及其模擬qsort函式的實作(基于冒泡排序),
📒博客主頁:未見花聞的博客主頁
🎉歡迎關注🔎點贊👍收藏??留言📝
📌本文由未見花聞原創,CSDN首發!
📆首發時間:🌴2021年9月7日🌴
??堅持和努力一定能換來詩與遠方!
💭參考書籍:📚《明解C語言》📚《C primer plus》
💬參考在線編程網站:🌐牛客網🌐力扣
🙏作者水平很有限,如果發現錯誤,一定要及時告知作者哦!感謝感謝!
博主的碼云gitee,平常博主寫的程式代碼都在里面,
📌導航小助手📌
- ??qsort庫函式
- 🍒函式宣告
- 🍒庫
- 🍒函式功能
- 🍒qosort函式各引數介紹
- 🍒compare函式
- 🍒測驗
- ??模擬實作qsort函式
- 🍋冒泡排序改裝思路
- 🍋冒泡排序模擬實作qsort函式
- 🍋測驗
??qsort庫函式
🍒函式宣告
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
🍒庫
<stdlib.h>
🍒函式功能
實作多個資料型別的快速排序,
🍒qosort函式各引數介紹
- 回傳型別:
void無回傳值 - 引數base:
void*無型別指標,可以接受任何指標型別,但是不能進行解參考,不能進行運算,該引數用來接受需要排序陣列的首地址, - 引數num:
size_t型別,本質上為無符號整型型別,該引數接受陣列中元素的數量, - 引數width:
size_t型別,本質上無符號整型型別,該引數接受陣列中元素的記憶體大小,單位為位元組, - 引數compare:函式指標型別,指向的函式型別為回傳值為
int,擁有2個引數的函式,其實這兩個引數型別都為const void指標,該函式用來比較兩個地址對應的元素的大小,該引數用來回呼compare所指向的函式,是實作多資料型別排序的核心,
🍒compare函式
在qsort函式中,其中一個引數是函式指標,指向一個用來比較兩個元素大小的函式,不妨記該函式的第一個引數為e1,第二個引數為e2,兩個引數均為只可讀無型別指標,該函式回傳值型別為int,記為x:
- x>0,表示
e1指向的元素大于e2指向的元素, - x=0,表示
e1指向的元素等于e2指向的元素, - x<0,表示
e1指向的元素小于e2指向的元素,
實作整型型別比較的compare函式:
如果qsort需要實作實作升序:
//升序
int compare(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
那需要實作降序呢?
其實很簡單,將上面return (*(int*)a - *(int*)b);改為return (*(int*)b - *(int*)a);就可以了,
實作浮點數比較的compare函式:
int compare_dou(const void* a, const void* b)
{
double com = (*(double*)a - *(double*)b);
//防止資料發生截斷造成排序結果錯誤
if (com > 0)
return 1;
else if (com < 0)
return -1;
else
return 0;
}
int compare_fla(const void* a, const void* b)
{
float com = (*(float*)a - *(float*)b);
//防止資料發生截斷造成排序結果錯誤
if (com > 0)
return 1;
else if (com < 0)
return -1;
else
return 0;
}
實作字符型別和字串比較的compare函式:
int compare(const void* a, const void* b)
{
return (*(char*)a - *(char*)b);
}
實作結構體型別比較compare函式:
//參考結構體
struct stu
{
char name[20];
int age;
double score;
};
int compare_stu(const void* a, const void* b)
{
//如果是字串
return strcmp(((struct stu*)a)->name, ((struct stu*)b)->name);
//如果整型
//return (((struct stu*)a)->age - ((struct stu*)b)->age);
//如果是浮點型
//float com = (*(float*)a - *(float*)b);
//防止資料發生截斷造成排序結果錯誤
//if (com > 0)
// return 1;
/*else if (com < 0)
return -1;
else
return 0;*/
}
🍒測驗
測驗主函式
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
//test;
}
測驗1:整數排序
void test1()
{
int arr[] = { 2,8,6,12,3,86,1,42,66,22,98,88 };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(int);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%d ", arr[i]);
}
qsort(arr, number, size, compare);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%d ", arr[i]);
}
}
陣列排序前:
2 8 6 12 3 86 1 42 66 22 98 88
陣列排序后:
1 2 3 6 8 12 22 42 66 86 88 98
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 37064)已退出,代碼為 0,
按任意鍵關閉此視窗. . .
測驗2:雙精度浮點數排序
void test2()
{
double arr[5] = { 3.5,8.9,9.2,4.8,2.1 };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(double);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%.2lf ", arr[i]);
}
qsort(arr, number, size, compare_dou);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%.2lf ", arr[i]);
}
}
陣列排序前:
3.50 8.90 9.20 4.80 2.10
陣列排序后:
2.10 3.50 4.80 8.90 9.20
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 9984)已退出,代碼為 0,
按任意鍵關閉此視窗. . .
測驗3:結構體中字串排序測驗
void test3()
{
struct stu arr[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(arr[0]);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%s ", arr[i].name);
}
qsort(arr, number, size, compare_stu);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%s ", arr[i].name);
}
}
陣列排序前:
zhangsan lisi wangwu
陣列排序后:
lisi wangwu zhangsan
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 29572)已退出,代碼為 0,
按任意鍵關閉此視窗. . .
??模擬實作qsort函式
經過對qsort函式的了解,我們發現該函式能夠對多種資料型別進行排序取決于傳入的函式指標引數,我們以冒泡排序為例,模擬實作qsort函式,
🍋冒泡排序改裝思路
先來看看冒泡排序函式
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//冒泡排序(int) 從小到大
void bubble_sort(int* arr, int size)
{
int i = 0;
for (i = 0; i < size - 1; i++)
{
int j = 0;
int flag = 1;//判斷資料是否發生交換,默認沒有發生交換
for (j = 0; j < size - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag)
break;
}
}
如果需要對多種資料型別進行排序,對應上面的這個冒泡排序,它所接受的引數肯定是必須改的,因為要接受多種資料型別的指標,所以傳入的指標必須是無具體型別void,函式內部中回圈排序的次數是沒有發生改變的,所以函式內部的兩層回圈是不用發生改變的,但是由于傳進來的是void型指標,無法進行運算和解參考,所以判斷陳述句是需要進行改動的,
🍋冒泡排序模擬實作qsort函式
對與if陳述句中所對應條件,我們可以呼叫compare函式,將陣列的前一個元素與后一個元素比較,如果該函式回傳值大于0,表示陣列前面的元素比后面的元素大,如果進行升序排列,我們需要對這兩個元素進行交換,這個交換我們不妨封裝在一個swap函式里,由于不知道資料型別,所以swap函式的引數為兩個元素的無型別地址,交換的時候我們不妨強制轉換為char*型別,因為char型別大小為1位元組,根據需要交換元素的大小,我們一個一個地將每個單位位元組的二進制序列交換,這樣就完成了交換,對于如何得到相鄰元素的首地址,同理我們先可以將傳入指標強制轉換為char*型別任何根據元素記憶體大小,計算的出每個元素的地址,比如陣列元素記憶體大小為width,則相鄰兩元素地址可以表示為(char*)val + j * width, (char*)val + (j + 1) * width,
知道了冒泡排序哪個地方需要改裝,我們來試著動手實踐一下,
typedef unsigned int sz_t;
void bubble_qsort(void* val, sz_t size, sz_t width, int (*cmp)(const void* p1, const void* p2))
{
sz_t i = 0;
for (i = 0; i < size - 1; i++)
{
sz_t j = 0;
sz_t flag = 1;
for (j = 0; j < size - 1 - i; j++)
{
if (cmp((char*)val + j * width, (char*)val + (j + 1) * width) > 0)
{
swap((char*)val + j * width, (char*)val + (j + 1) * width, width);
flag = 0;
}
}
if (flag)
break;
}
}
void swap(char* buf1, char* buf2, sz_t width)
{
sz_t i = 0;
for (i = 0; i < width; i++)
{
char tmp = *(buf1 + i);
*(buf1 + i) = *(buf2 + i);
*(buf2 + i) = tmp;//交換每單位位元組對于的二進制序列
}
}
這樣,冒泡排序就能排序多種資料型別,模擬實作了qsort函式,當然也可以使用其他的排序方法模擬實作qsort函式,
🍋測驗
測驗主函式
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
//test;
}
測驗1:整數排序
void test1()
{
int arr[] = { 2,8,6,12,3,86,1,42,66,22,98,88 };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(int);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%d ", arr[i]);
}
bubble_qsort(arr, number, size, compare);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%d ", arr[i]);
}
}
陣列排序前:
2 8 6 12 3 86 1 42 66 22 98 88
陣列排序后:
1 2 3 6 8 12 22 42 66 86 88 98
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 10620)已退出,代碼為 0,
按任意鍵關閉此視窗. . .
測驗2:雙精度浮點數排序
void test2()
{
double arr[5] = { 3.5,8.9,9.2,4.8,2.1 };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(double);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%.2lf ", arr[i]);
}
bubble_qsort(arr, number, size, compare_dou);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%.2lf ", arr[i]);
}
}
陣列排序前:
3.50 8.90 9.20 4.80 2.10
陣列排序后:
2.10 3.50 4.80 8.90 9.20
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 34200)已退出,代碼為 0,
按任意鍵關閉此視窗. . .
測驗3:結構體中字串排序測驗
void test3()
{
struct stu arr[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} };
sz_t number = sizeof(arr) / sizeof(arr[0]);
sz_t size = sizeof(arr[0]);
sz_t i = 0;
printf("陣列排序前:\n");
for (i = 0; i < number; i++)
{
printf("%s ", arr[i].name);
}
bubble_qsort(arr, number, size, compare_stu);
printf("\n陣列排序后:\n");
for (i = 0; i < number; i++)
{
printf("%s ", arr[i].name);
}
}
陣列排序前:
zhangsan lisi wangwu
陣列排序后:
lisi wangwu zhangsan
D:\gtee\C-learning-code-and-project\練習使用qsort\Debug\練習使用qsort.exe (行程 13512)已退出,代碼為 0,
按任意鍵關閉此視窗. .
關于qsort的內容就分享到這了!當然如果對快速排序感興趣,可以自己使用其他的排序方法模擬實作qsort函式!還請大家多多支持!感謝感謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/298354.html
標籤:java
上一篇:瀘職院一年學習總結
