C语言:qsort详解 并实现--整形 浮点数 字符 字符串 结构体排序
一.qsort函数详解
1.1 简介
- qsort是C语言库函数中的一个排序函数,底层逻辑是
快速排序(quick sort)
- 头文件
<stdlib.h>
- 功能:排序任意类型的数组元素
1.2 函数声明及参数详解
void qsort(void* base, //指向待排序数组的第一个元素的指针
size_t num, //base指向数组中的元素个数
size_t size,//base指向的数组中一个元素的大小 单位是字节
int (*compar)(const void*, const void*)
//compar是函数指针,指向一个比较两个元素的函数(回调函数)
)
1.3 回调函数
回调函数
:一个通过函数指针调用的函数
如果把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应
1.4 compar参数
函数原型: int compar(const void*p1, const void*p2)
- compar参数是函数指针,指向一个比较两个元素的函数,这个函数是自定义的,根据用户想比较的数据类型进行变换,这里称它所指向的函数也为compar。
注意
:
两个形参必须得是const void*类型,再在自定义的比较函数内部将const void*强制转换为需要的类型(void*类型的指针可以接收任意类型的地址,但不能对其解引用和加减整数)返回值
:
如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的左面;
如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定;
如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的右面。
因此可直接通过获取p1与p2指向的数据作差(即分别强转>>解引用>>作差)即可
通过这些可以观察到qsort默认升序,若想获得降序只需p1和p2更换位置即可
以整型数组为例:
int cmp_int(const void*a, const void*b)
{
//return *(int*)a - *(int*)b;//升序
return *(int*)b - *(int*)a;//降序
}
二.整型排序
代码如下:
#include <stdio.h>
#include <stdlib.h>
void Print1(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
int cmp_int(const void*a, const void*b)
{
//return *(int*)a - *(int*)b;//升序
return *(int*)b - *(int*)a;//降序
}
void test1()
{
int arr[] = { 3,1,5,11,2,0,13,7,9,21,17 };
int sz = sizeof(arr) / sizeof(arr[0]);
Print1(arr, sz);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
Print1(arr, sz);
}
int main()
{
test1();
return 0;
}
三.浮点数排序
代码如下:
#include <stdio.h>
#include <stdlib.h>
void Print2(float* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%f ", *(arr + i));
}
printf("\n");
}
int cmp_float(const void* a, const void* b)
{
//return *(float*)a - *(float*)b;//升序
return *(float*)b - *(float*)a;//降序
}
void test2()
{
float arr[5] = { 0 };
printf("请输入你想排序的5个浮点数:");
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
scanf("%f", &arr[i]);
//注意这里的占位符是%f 且后面不能有空格 不然输入的时候会出现问题
}
qsort(arr, sz, sizeof(arr[0]), cmp_float);
Print2(arr, sz);
}
int main()
{
test2();
return 0;
}
四.字符排序
注意: 使用scnaf输入字符时应使用%c,但要注意%c不会忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格,所以注意输入多个字符时,中间别包含空格,不然%c会把空格也读上,如果要强制跳过字符前的空白字符,可以写成在%c前加一个空格
代码如下:
#include <stdio.h>
#include <stdlib.h>
void Print3(char* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%c ", *(arr + i));
}
printf("\n");
}
int cmp_char(const void* a, const void* b)
{
//return *(char*)a - *(char*)b;//升序
return *(char*)b - *(char*)a;//降序
}
void test3()
{
char arr[5] = { 0 };
printf("请输入你想排序的5个字符:");
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)//i是什么类型没有太大影响 它只影响循环次数
{
scanf("%c", arr+i);//不会忽略空格 输入abcde 才会正常打印e d c b a
//scanf(" %c", arr+i);//写成这样会强制跳过空格 输入a b c d e 会正常打印e d c b a
}
qsort(arr, sz, sizeof(arr[0]), cmp_char);
Print3(arr, sz);
}
int main()
{
test3();
return 0;
}
五.字符串排序
- 两个字符串比较相等时,不是使用==,而是使用库函数
strcmp
,头文件<string.h>
函数原型:int strcmp(const char*s1, const char*s2)
返回值:当s1<s2时,返回负数; 当s1=s2时,返回0; 当s1>s2时,返回正数;
正好与比较函数的返回值匹配
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Print5(char* arr[], int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%s ", arr[i]);
}
printf("\n");
}
int cmp_char(const void* p1, const void* p2)
{
return strcmp((char*)p1, (char*)p2);
}
void test5()
{
char* arr[5] = { "aaaaa", "aaaab", "aaabb", "aabbb", "abbbb" };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_char);
Print5(arr, sz);
}
int main()
{
test5();
return 0;
}
六.结构体排序
- 结构体有许多成员,可根据不同成员进行排序
- 注意: 要么结构体定义在最前面,要么就前面放上结构体声明,不然后续使用结构体时会报错
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student
{
char name[20];
int age;
float score;
};
void Print(struct Student* arr, int sz, char* x)
{
printf("根据%s排序:", x);
if (strcmp(x, "name") == 0)
{
for (int i = 0; i < sz; i++)
{
printf("{%s,%d,%f} ", arr[i].name,arr[i].age, arr[i].score);
}
printf("\n");
}
else if (strcmp(x, "age") == 0)
{
for (int i = 0; i < sz; i++)
{
printf("{%s,%d,%f} ", arr[i].name, arr[i].age, arr[i].score);
}
printf("\n");
}
else
{
for (int i = 0; i < sz; i++)
{
printf("{%s,%d,%f} ", arr[i].name, arr[i].age, arr[i].score);
}
printf("\n");
}
}
//strcmp函数原形:int strcmp(const char*string1, const char*string2)
//注意括号里参数是指针变量
int cmp_struct_name(const void* a, const void* b)
{
//return strcmp(((struct Student*)a)->name, ((struct Student*)b)->name);//升序
return strcmp(((struct Student*)b)->name, ((struct Student*)a)->name);//降序
//结构体间接访问操作符:结构体指针->成员名
//结构体直接访问操作符:结构体名.成员名
}
int cmp_struct_age(const void* a, const void* b)
{
//return ((struct Student*)a)->age - ((struct Student*)b)->age;//升序
return ((struct Student*)b)->age - ((struct Student*)a)->age;//降序
}
int cmp_struct_score(const void* a, const void* b)
{
//return ((struct Student*)a)->score - ((struct Student*)b)->score;//升序
return ((struct Student*)b)->score - ((struct Student*)a)->score;//降序
}
void test4()
{
struct Student arr[] = {{"Bob", 20, 86.3},{"Mary", 19, 54.1},{"Lucy",18, 95.2}};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_struct_name);
Print(arr, sz, "name");
qsort(arr, sz, sizeof(arr[0]), cmp_struct_age);
Print(arr, sz, "age");
qsort(arr, sz, sizeof(arr[0]), cmp_struct_score);
Print(arr, sz, "score");
}
int main()
{
test4();
return 0;
}
创作不易,希望大家多多支持,有什么观点欢迎讨论🌹🌹