【C库函数】qsort函数详解

简介: 函数是基于快速排序算法实现的一个排序函数

qsort

       函数是基于快速排序算法实现的一个排序函数

5db8ac2859e3510e489811944a1330f8_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

函数基本原型

 

void qsort( void *base,
                      size_t num,
                      size_t width,
                      int (*cmp )(const void *elem1, const void *elem2 ) //函数指针
                     );

参数解读

参数 base num width cmp elem1  、elem2
解释 待排序数据的起始位置 数组的元素个数 一个元素的字节大小 比较函数 待比较的两个元素的位置

cmp函数返回值

ced58387f134c4d1bdce00486cb9cb88_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

函数详解

接下来我将用下面伪代码为例讲解qsort函数

void test2()
{
  int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
  //排序为升序
  int sz = sizeof(arr) / sizeof(arr[0]);
}

当我们要为该数组从小到大排序,该给qsort函数传参呢?


void qsort( void *base,


                     size_t num,


                     size_t width,


                     int (*cmp )(const void *elem1, const void *elem2 ) //函数指针


                    );


我们看函数原型,qsort第一个参数是‘待排序数据的起始位置’,而数组名又是数组首元素地址,所以第一个传的参数是‘arr’   【qsort( arr , , ,  )】


然后我们看第二个参数,是‘数组的元素个数’,而sz = sizeof(arr) / sizeof(arr[0])算的就是数组的个数,所以第二个传的参数是‘sz’  【qsort( arr , sz , ,  )】


接下来我们看第三个参数,是‘一个元素的字节大小’,而sizeof(arr[0])就是数组包含元素字节的大小,所以第三个传的参数是‘sizeof(arr[0])’    【qsort( arr , sz , sizeof(arr[0]) ,  )】


最后也是最难的部分,第四个参数是‘函数指针’,所以我们要传进去一个函数地址过去。


       这个地方要求qsort函数的使用者,自定义一个比较函数!


       为什么呢这个函数要我们自定义呢?


当我们排序整型元素时,两个元素用大于号或小于号比较就行了。但是,如果我们排序的是结构体数据呢,如果这个结构体表示的是学生的话,那我们是拿名字来排呢?还是拿身高或年龄或其他的来排序呢?这个时候是不是就要指定一个排序的方法!


       所以使用这根据实际情况,提供一个函数,实现两个数据的比较,到这这个比较函数算是叙述清楚了。


假设我们定义这个比较叫函数cmp_int


这函数的第一个参数就为consrt* void e1,第二个参数为const void* e2


int cmp_int(const void* e1, const void* e2)

所以qsort函数内的传参就完整了【qsort( arr , sz , sizeof(arr[0]) , cmp_int )】


比较函数实现并解读

int cmp_int(const void* e1, const void* e2)


如果我们先把9和8分别传递给e1、e2,然后进行比较并传递一个结果。


那问题来了,怎么样比较呢?


可能有读者回想直接用if语句判断然后retrun返回

if (*e1 > *e2)
  {
  return ;
  }

其实感觉上这个逻辑是同的,但实际上这样写是不正确的,同时编译会报如下错误。

96bb80b0cf062d7cc1af0297194f2ca5_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

意思就是e1是一个void指针,是一个无确切类型的指针。它是不能直接解引用的


加入有一个指针,定义为int* e3。当我们解引用e3(*e3)时,指针解引用是不是访问4个字节(指针为int*类型的  如果是char* 那就访问1个字节 类推)


而对于void*的指针是不能直接解引用的,那void类型有什么用吗?我们可以把void* 的指针比喻成垃圾桶,什么东西都可以往里面丢。也就是说void*指针可以接受任意类型的地址,但是让void* 指针加1,抱歉它也不知道要访问几个字节,同样解引用也是不正当的。

176cf93f4a44efa79a4a7b958be918f8_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_18,color_FFFFFF,t_70,g_se,x_16.png

那要void* 指针要怎么用呢?我们可以强制类型转换然后再解引用,这样就可以得到两个数比较的结果了。 那比较函数就可以这样写

eac44459e438d4891d82a794c8a061d1_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png


但是这样写比较函数有点过于复杂,我们可以稍微优化一下

54a38d2af10111a328ef7306fd9c63f2_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png



到这比较函数就算是写完了!


qsort函数排序代码实现并展示结果

1、排序整型数组

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* e1, const void* e2)
{
  return (*(int*)e1 - *(int*)e2);
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++) {
  printf("%d ", arr[i]);
  }
  printf("\n");
}
void test1()
{
  int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
  //排序为升序
  int sz = sizeof(arr) / sizeof(arr[0]);
  qsort(arr, sz, sizeof(arr[0]), cmp_int);
  print_arr(arr, sz);
}
int main()
{
  test1();
  return 0;
}

2、排序结构体

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//排序结构体
struct Stu
{
  char name[20];
  int age;
  double score;
};//定义结构体变量
//比较函数
int cmp_stu_by_age(const void* e1,const void* e2)
{
  return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;//升序排列成绩
}
int cmp_stu_by_name(const void* e1, const void* e2)
{
  return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//比较两个字符串不能直接相减,可以用strcmp函数进行比较,如果e1和e2交换,那么就是降序
}
int cmp_stu_by_score(const void* e1, const void* e2)
{
  return (int)(((struct Stu*)e2)->score - ((struct Stu*)e1)->score);//降序排列成绩
}
//打印
void print_age(struct Stu arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
  printf("%d ", arr[i].age);
  }
  printf("\n");
}
void print_name(struct Stu arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
  printf("%s ", arr[i].name);
  }
  printf("\n");
}
void print_score(struct Stu arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
  printf("%.1f ", arr[i].score);
  }
  printf("\n");
}
void test2()
{
  struct Stu arr[4] = { {"qinqin",21,98.8},{"xiaozhu",20,88.0},{"laohei",22,60.1},{"zhangheng",30,74.3} };
  int sz = sizeof(arr) / sizeof(arr[0]);
  //按成绩升序排
  qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
  print_age(arr, sz);
  //按名字升序排
  qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
  print_name(arr, sz);
  //按成绩降序排
  qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_score);
  print_score(arr, sz);
}
int main()
{
  test2();
  return 0;
}


相关文章
|
9月前
用冒泡排序完成库函数qsort的作用
用冒泡排序完成库函数qsort的作用
|
9月前
|
C语言
C语言库函数之 qsort 讲解、使用及模拟实现(下)
C语言库函数之 qsort 讲解、使用及模拟实现(下)
39 0
|
8月前
|
C语言
qsort函数(c语言详解)
qsort函数(c语言详解)
53 0
|
8月前
|
搜索推荐 C语言
C语言——qsort函数的使用(详解)
C语言——qsort函数的使用(详解)
|
5天前
|
搜索推荐 C语言
c语言qsort函数的模拟实现
c语言qsort函数的模拟实现
9 1
|
5天前
|
C语言
【C语言】: 快速排序——qsort函数的介绍
【C语言】: 快速排序——qsort函数的介绍
7 0
|
11月前
|
C语言
【C语言】带你玩转库函数qsort
【C语言】带你玩转库函数qsort
76 0
|
9月前
|
存储 C语言
C语言库函数之 qsort 讲解、使用及模拟实现(上)
C语言库函数之 qsort 讲解、使用及模拟实现
72 0
|
9月前
|
C语言
(C语言)qsort函数的使用
1.qsort函数的介绍 2.qsort函数的声明 3.qsort函数的使用 1.整形 2.浮点型 3.结构体类型 (1)一级排序 (2)多级排序
51 0
|
10月前
|
C语言
【C语言】轻松模拟实现qsort函数
【C语言】轻松模拟实现qsort函数
96 0