小編給大家分享一下C語言中如何使用qsort函數,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
我們可以使用 搜索庫函數網址或者MSDN軟件進行查找。
qsort()函數:快速排序的函數 -引用stdlib.h頭文件

參數說明:
void qsort ( void* base, //要排序的目標數組 size_t num, //待排序的元素個數 size_t width, //一個元素的大小,單位是字節 int(*cmp)(const void* e1, const void* e2) );
其中cmp是函數指針,cmp指向的是:排序時,用來比較兩個元素的函數。需要自己編寫。
返回值:

關于void*型指針:
void*:無具體類型的指針 能夠接收任意類型的地址
缺點:不能進行運算。不能+-整數,不能解引用
int a = 0; float f = 5.5f; void* p1 = &a; void* p2 = &f; p1 = p1+1; //err
注意:
1.比較函數的參數類型為void* ,我們要進行強制類型轉換!且要解引用才能得到對應的值!
2.若我們想排成降序,只需要寫成e2-e1即可
void Print(int* arr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
//比較整形
//注意類型時void* 所以要強制類型轉化,還要解引用才是對應的值?。?!
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
void test1()
{
int arr[] = { 9,8,7,6,7,5,4,8 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
Print(arr, sz);
}注意使用sizeof()操作符和strlen()函數的區別
//注意要要強制類型轉換??! 要解引用?。?! 本質上是比較Ascii值
int cmp_char(const void* e1, const void* e2)
{
return *(char*)e1 - *(char*)e2;
}
void test4()
{
char arr[] ="mango";
//若使用sizeof計算長度:
//int sz = sizeof(arr) / sizeof(arr[0]); //6
//qsort(arr, sz-1, sizeof(arr[0]), cmp_float);
//因為sizeof把\0也算進去了,所以計算出來的值比字符串本身長度多1
int sz = strlen(arr); //5
qsort(arr, sz, sizeof(arr[0]), cmp_char);
printf("%s\n",arr);
}先看看下面這段程序有沒有問題?
int cmp_chars(const void* e1, const void* e2)
{
return strcmp((char*)e1, *(char*)e2);
}
void test2()
{
char* arr1 = "abc";
char* arr2 = "wcad";
char* arr3 = "cab";
char* p[3] = { arr1,arr2,arr3 };
int sz = sizeof(p) / sizeof(p[0]);
qsort(p, sz, sizeof(p[0]), cmp_chars);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s\n", p[i]);
}
}打印出來發現:結果是錯誤的!

->調試后發現:e2存放的是p的地址(char**類型),e1存放的是p指向的下一個元素的地址(char**類型)
對于這種寫法,傳進去的是p的地址,strcmp()會將p地址對應的內容轉化成字符串,也就是將p中arr1,arr2,arr3的地址轉化成字符串
實際上應該傳p地址空間中arr1,arr2的地址,這樣strcmp()才能找到arr1和arr2對應的字符串,因此得先把e1,e2轉化成char**,這樣解引用以后才是一個char*的地址
原因:把p傳給qsort,p是數組名->首元素地址,元素類型為char*>,所以p的類型為:char**類型。 所以e1 和e2也要強制類型轉化為char**,解引用e1,e2才是對應字符串的地址!

正解:
int cmp_chars(const void* e1, const void* e2)
{
return strcmp(*(char**)e1, *(char**)e2);
}
void test2()
{
char* arr1 = "abc";
char* arr2 = "wcad";
char* arr3 = "cab";
char* p[3] = { arr1,arr2,arr3 };
int sz = sizeof(p) / sizeof(p[0]);
qsort(p, sz, sizeof(p[0]), cmp_chars);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s\n", p[i]);
}比較年齡->實際比較的是整形
比較名字->實際比較的是字符串->使用strcmp函數,不能使用 == 判斷
struct Stu
{
int age;
char name[20];
};
//比較結構體中元素的年齡
int cmp_age(const void* e1, const void* e2)
{
//本質是比較整形
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//比較名字
int cmp_name(const void* e1, const void* e2)
{
//本質是字符串比較->使用strcmp函數
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test2()
{
//創建結構體數組,用大括號初始化
struct Stu s[3] = { {19,"Mango"},{18,"Lemon"},{20,"Hello"} };
int sz = sizeof(s) / sizeof(s[0]);
//以年齡排
qsort(s, sz, sizeof(s[0]), cmp_age);
printf("%s %d ",s[0].name,s[0].age);
printf("%s %d ", s[1].name, s[1].age);
printf("%s %d ", s[2].name, s[2].age);
printf("\n");
//以姓名排
qsort(s, sz, sizeof(s[0]), cmp_name);
printf("%s %d ", s[0].name, s[0].age);
printf("%s %d ", s[1].name, s[1].age);
printf("%s %d ", s[2].name, s[2].age);
printf("\n");
}注意:比較函數中,返回類型是int,最后相減的值要強制類型轉化為int ,但這也會造成錯誤,建議使用方法2.
//寫法1:可能會出錯
// 原因: 0.2 -0.1 = 0.1 強制類型轉化為int后 結果為0
//int cmp_float(const void* e1, const void* e2)
//{
// //返回類型是int 所以相減后的結果要強制類型轉化
// return (int)(*(float*)e1 - *(float*)e2);
//}
//寫法2:對應上qsort的返回值
int cmp_float(const void* e1, const void* e2)
{
if ((*(float*)e1 - *(float*)e2) > 0.00000)
return 1;
else if ((*(float*)e1 - *(float*)e2) == 0.000000)
return 0;
else
return -1;
}
void test3()
{
float arr[5] = { 5.01f,5.01f,0.02f,0.01f,5.001f };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%f ", arr[i]);
}
}
主要思想:相鄰的兩個元素進行比較

對于冒泡排序: n個元素 共進行n-1趟冒泡排序。一趟可以使一個元素在特定位置上,每趟排序可以少比較一個元素
但是冒泡排序只能排序整形
void BubbleSort(int* arr, int sz)
{
int i = 0;
int j = 0;
int flag = 1;//假設一開始有序
//共進行sz-1趟
for (i = 0; i < sz-1; i++)
{
// 每一趟
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;
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
int main()
{
int arr[10] = { 2,3,6,7,9,0,0,3,2,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, sz);
return 0;
}qsort庫函數使用的是什么參數,我們設計的函數就使用什么參數!
1.為何將base強制類型轉化為char*型指針:
原因:char* 指針+1跳過一個字節,+width:跳過width個字節,指向下一個元素。轉化為其他類型不合適
2. 交換函數:還要把寬度(每個元素所占字節數)傳過去
因為交換的時候是傳地址,所以要知道元素的寬度,一個字節一個字節的交換 ,這樣也證明了使用char*指針的好處!
3.(char*)base + j * width, (char*)base + (j + 1) * width,
當j = 0時:比較的是第一個元素和第二個元素
j = 1時,比較的是第二個元素和第三個元素
.... 很妙的寫法
//交換 --一個字節一個字節的交換,共交換width次
void Swap(char* buf1, char* buf2, size_t width)
{
size_t i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2))
{
//冒泡排序
//若要排序n個元素,只需要進行n-1趟
//每一趟可以少比較一個元素,每一趟可以使一個元素在確定的位置上
//num:要排序元素的個數 類型是size_t
//num是無符號數 防止產生警告 所以i和j也定義為size_t
// size_t == unsigned int
size_t i = 0;
size_t j = 0;
//共進行num-1趟
for (i = 0; i < num; i++)
{
//每一趟
for (j = 0; j < num - 1 - i; j++)
{
//比較
//傳地址
//相鄰兩個元素比較 width:寬度,每個元素所占字節
//排成升序
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
//交換兩數
Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );
}
}
}
}當然 ,交換也可以使用庫函數memcpy

dest:目標空間
src:要拷貝到目標空間的字符 -因為不作修改,所以可以用const修飾
count:字節數
char tmp [30]; //防止結構體類型之類的類型 臨時空間 memcpy(tmp, (char*)base + j * size, size); memcpy( (char*)base + j * size, (char*)base + (j + 1) * size, size); memcpy( (char*)base + (j + 1) * size, tmp, size);
以上是“C語言中如何使用qsort函數”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。