qsort函数的应用以及模拟实现

简介: qsort函数的应用以及模拟实现

一、qsort函数介绍


库函数查询网站(建议使用旧版本查询)



头文件:<stdlib.h>



功能介绍:


使用函数确定顺序,对指向的数组的元素进行排序,每个元素的长度以字节为单位。


此函数使用的排序算法通过调用指定的函数(要自己定义元素比较方式函数传给qsort)并将指向元素的指针作为参数来比较元素.


该函数不返回任何值,而是通过按定义重新排序数组元素来修改指向的数组的内容。


参数介绍:


参数1(void* base) 要排序的数组首地址
参数2(size_t num) 数组中的元素个数。
参数3(size_t size) 数组中每个元素的大小(以字节为单位)。
参数4 ( int (compar)(const void,const void*)) 指向数组中元素比较方式的函数指针


二、qsort函数的应用


1.整形数组排序


#include <stdio.h>
#include <stdlib.h>
//注意,由于qsort排序时,并不知道要排序的元素是何种类型,
//所以自定义比较函数的参数都暂时是void*要强制类型转化为对应类型才可以使用.
int int_sort(const void* e1, const void* e2)//自定义整形元素比较方式函数
{
  return  *(int*)e1 - *(int*)e2;
}
int main()
{
  int arr1[10] = { 4,6,1,7,8,2,9,10,3,5 };
  int sz1 = sizeof(arr1) / sizeof(arr1[0]);//计算元素个数
  qsort(arr1, sz1, sizeof(arr1[0]), int_sort);//整形排序
  int i = 0;
  for (i = 0; i < sz1; i++)//整形打印
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}


运行结果:


1 2 3 4 5 6 7 8 9 10


2.浮点型数组排序


//浮点型数组排序
#include <stdio.h>
#include <stdlib.h>
int double_sort(const void* e1, const void* e2)//浮点型比较
{
//注意要强制转化为相对于的类型,然后解引用比较.
  int ret = 0;
  if ((*(double*)e1) - (*(double*)e2) > 0)
  {
    ret = 1;//前面的数比后面大时返回整数
  }
  else ret = -1;//后面数大返回负数;
  return ret;//两个数相等返回0;
}
int main()
{
  double arr2[6] = {3.41, 9.45, 4.78, 3.67, 2.9,  7.36 };
  int sz2 = sizeof(arr2) / sizeof(arr2[0]);//计算数组元素个数
  qsort(arr2, sz2, sizeof(arr2[0]), double_sort);
  int i = 0;
  for (i = 0; i < sz2; i++)//浮点型数组打印
  {
    printf("%5.2lf ", arr2[i]);
  }
  return 0;
}


运行结果:


2.90 3.41 3.67 4.78 7.36 9.45


3.字符型排序


//字符型数组排序
#include <stdio.h>
#include <stdlib.h>
int char_sort(const void* e1, const void* e2)//字符型比较
{
  return (*(char*)e1) - (*(char*)e2);
}
int main()
{
  char arr3[10] = { 'd','g','b','a','e','i','h','c','j','f' };
  int sz3 = sizeof(arr3) / sizeof(arr3[0]);//计算元素个数
  qsort(arr3, sz3, sizeof(arr3[0]), char_sort);
  int i = 0;
    for (i = 0; i < sz3; i++)//字符型打印
  {
    printf("%c ", arr3[i]);
  }
}


运行结果:


a b c d e f g h i j


4.结构体数组排序


strcmp函数用于比较字符串的,它的比较方式是比较字符的ASCII码值,并不是长度,后续在库函数模拟篇会讲到.


//结构体排序
#include <stdio.h>
#include <stdlib.h>
struct student//创建结构体类型
{
  char name[15];
  char sex[3];
  int age;
  float stature;
};
typedef struct student sc;//对结构体类型重命名
int sort_age(const void* e1, const void* e2)//按年龄排序
{
  return (((sc*)e1)->age - ((sc*)e2)->age);
}
int sort_name(const void* e1, const void* e2)//按姓名排序
{
  return strcmp(((sc*)e1)->name, ((sc*)e2)->name);
}
int main()
{
    sc arr4[5] = { {"chu jie niu","男",20,1.73f},
        {"xiao wang","男",19,1.68f},
        {"qing niao","女",21,1.59f},
        {"wao shu li","男",16,1.83f},
      {"peng hu wan","男",15,1.81f} };
    int sz4 = sizeof(arr4) / sizeof(arr4[0]);
    //qsort(arr4, sz4, sizeof(arr4[0]), sort_age);
    qsort(arr4, sz4, sizeof(arr4[0]), sort_name);
    int i = 0;
    printf("姓名      性别   年龄   身高\n");
    for (i = 0; i < sz4; i++)
    {
      printf("%-12s %-5s %-5d %-5.2fm\n", arr4[i].name, arr4[i].sex, arr4[i].age, arr4[i].stature);
    }
    return 0;
}


运行结果:


姓名        性别   年龄   身高
chu jie niu  男    20    1.73 m
peng hu wan  男    15    1.81 m
qing niao    女    21    1.59 m
wao shu li   男    16    1.83 m
xiao wang    男    19    1.68 m


三、qsort模拟实现(采用冒泡排序模拟)


复习一下冒泡排序吧!


void bubble_sort(int* arr, int sz)//冒泡排序
{
  int i = 0, j = 0;
  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;
      }
    }
  }
}
int main()
{
  int arr[10] = { 4,7,1,8,2,3,9,10,5,6 };
  int sz = sizeof(arr) / sizeof(arr[0]);//计算元素个数
  bubble_sort(arr, sz);
  for (int i = 0; i < sz; i++)//数组打印
  {
    printf("%d ",arr[i]);
  }
  return 0;
}


qsort模拟实现(采用冒泡排序模拟实现)


第一步:冒泡函数的参数


首先,要修改的是冒泡排序函数的参数.


void bubble_sort(void * arr, size_t num, size_t width, int (cmp)(const void, const void*))


这四个参数的含义上面介绍qsort参数时有介绍.


需要注意的是,qsort函数事先并不知道要传过来的数组是何种类型,所以先用void*接收.


补充知识:


void*可以接收任何类型的变量,但是并不能直接使用,要强制类型转化为对应类型使用.


第二步:比较元素的的方法


if (arr[j] > arr[j + 1])


语句中的arr[j]和arr[j+1]有两点需要注意.


由于事先不知道类型


1.要先将arr强制类型转化为char*,因为一个字节是类型的最小单位,这时width就发挥作用了.


arr[j]转化为 (char*)arr + j * width


arr[j+1]转化为 (char*)arr + (j + 1) * width



2.元素的比较方式不再是单一的相减就可以,这里就用到了自定义函数,元素的比较方式函数.


if (cmp((char*)arr + j * width, (char*)arr + (j + 1) * width) > 0)


第三步:交换函数


对于这样只能实现整形的交换方式,肯定是不行的.


int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;


修改为:用char*类型修改交换


swap(char* e1, char* e2, size_t sz)//交换函数
{
  //由于qsort函数事先不知道要比较的元素是何种类型,所以用最小单位一个字节来交换.
  //sz代表元素的所占字节大小
  int i = 0;
  char p = 0;
  for (i = 0; i < sz; i++)
  {
    p = *(e1 + i);
    *(e1 + i) = *(e2 + i);
    *(e2 + i) = p;
  }
}


最后展示全部代码:


#include <stdio.h>
#include <stdlib.h>
struct student//创建结构体类型
{
  char name[15];
  char sex[3];
  int age;
  float stature;
};
typedef struct student sc;//对结构体类型重命名
int sort_age(const void* e1, const void* e2)//按年龄排序
{
  return (((sc*)e1)->age - ((sc*)e2)->age);
}
int sort_name(const void* e1, const void* e2)//按姓名排序
{
  return strcmp(((sc*)e1)->name, ((sc*)e2)->name);
}
int int_sort(const void* e1, const void* e2)//整形比较
{
  return  *(int*)e1 - *(int*)e2;
}
swap(char* e1, char* e2, size_t sz)//交换函数
{
  //由于qsort函数事先不知道要比较的元素是何种类型,所以用最小单位一个字节来交换.
  //sz代表元素的所占字节大小
  int i = 0;
  char p = 0;
  for (i = 0; i < sz; i++)
  {
    p = *(e1 + i);
    *(e1 + i) = *(e2 + i);
    *(e2 + i) = p;
  }
}
//最后一个参数是函数指针,指向两个元素的比较方法这个函数
void bubble_sort(void * arr, size_t num, size_t width, int (*cmp)(const void*, const void*))
{
  int i = 0, j = 0;
  for (i = 0; i < num-1; i++)
  {
    for (j = 0; j < num - 1 - i; j++)
    {
      if (cmp((char*)arr + j * width, (char*)arr + (j + 1) * width) > 0)
      {
        swap((char*)arr + j * width , (char*)arr + (j + 1) * width,width);
      }
    }
  }
}
int main()
{
  int arr[10] = { 4,7,1,8,2,3,9,10,5,6 };
  int sz = sizeof(arr) / sizeof(arr[0]);//计算元素个数
  bubble_sort(arr,sz,sizeof(arr[0]),int_sort);
  for (int i = 0; i < sz; i++)//数组打印
  {
    printf("%d ",arr[i]);
  }
  printf("\n");
  sc arr4[5] = { {"chu jie niu","男",20,1.73f},
    {"xiao wang","男",19,1.68f},
    {"qing niao","女",21,1.59f},
    {"wao shu li","男",16,1.83f},
  {"peng hu wan","男",15,1.81f} };
  int sz4 = sizeof(arr4) / sizeof(arr4[0]);
  qsort(arr4, sz4, sizeof(arr4[0]), sort_age);
  //qsort(arr4, sz4, sizeof(arr4[0]), sort_name);
  int i = 0;
  printf("姓名      性别   年龄   身高\n");
  for (i = 0; i < sz4; i++)
  {
    printf("%-12s %-5s %-5d %-5.2fm\n", arr4[i].name, arr4[i].sex, arr4[i].age, arr4[i].stature);
  }
  return 0;
}


运行结果:


1 2 3 4 5 6 7 8 9 10
姓名        性别   年龄   身高
peng hu wan  男    15    1.81 m
wao shu li   男    16    1.83 m
xiao wang    男    19    1.68 m
chu jie niu  男    20    1.73 m
qing niao    女    21    1.59 m
目录
相关文章
|
4月前
|
Arthas SQL Java
Arthas ognl 表达式从入门到实战:掌握在线调试最强的表达式引擎
Arthas ognl 表达式:不重启 JVM 就能访问任意对象、调用任意方法。从零讲透 OGNL 语法与 Arthas ognl 命令实战
Arthas ognl 表达式从入门到实战:掌握在线调试最强的表达式引擎
|
5月前
|
机器学习/深度学习 数据可视化 测试技术
YOLO26如何涨点系列篇(NEU-DET缺陷检测) | CVPR2026 FAAFusion 解决Neck跨尺度方向冲突,实现涨点1.2%
在NEU-DET数据集下验证:原始mAP50原始为 0.722提升至 0.734 ,P 原始为  0.745 提升至   0.749, R 原始为 0.643 提升至0.665 , mAP50-95原始为0.407提升至 0.41
537 3
|
5月前
|
人工智能 缓存 开发框架
阿里云Qwen3.7-Max限时优惠:5折起,输入6元/每百万tokens,输出18元/每百万tokens
Qwen3.7-Max是通义千问面向智能体时代的旗舰大模型,在编程能力(Code Arena全球第二)、智能体执行、长程推理及多语言理解等维度均达行业顶尖水平,支持1M token超长上下文、35小时长周期自主执行及1158次工具调用,已在蔚来汽车工程中验证AI代码生成占比超70%。当前限时5折,输入6元/百万tokens、输出18元/百万tokens,全模型通用节省计划低至4.5折,新用户还可享100万免费tokens(90天有效)。无论开发者探索AI编程,还是企业构建智能体系统,Qwen3.7-Max都是当下高性价比的全能之选。
|
关系型数据库 MySQL 数据处理
基于python的化妆品销售分析系统
本项目基于Python构建化妆品销售分析系统,结合Django框架与MySQL数据库,实现销售数据的采集、处理、分析与可视化,助力企业精准营销与决策优化,推动化妆品行业数字化转型。
|
12月前
|
监控 测试技术 API
人为漏测防不住?让Dify工作流成为你的“测试策略大脑”,7x24小时在线排查
在软件测试中,人为疏漏难以避免。本文介绍如何用Dify工作流构建“测试策略大脑”,将专家经验固化为自动化分析系统,实现代码变更智能评估、测试重点推荐,7x24小时守护质量,让测试更精准高效。
|
10月前
|
JavaScript 前端开发 数据可视化
如何优雅地处理Echarts环形图中的小数显示?
本文介绍了在数据可视化中处理数字格式的三种方法,重点解决保留两位小数并去除末尾多余0的问题。通过字符串操作、正则表达式和Number类型转换,实现简洁高效的数字格式化,推荐使用Number方法最优。
373 0
|
Python
【金融量化】通道突破策略之布林带策略(Bollinger Band )、肯特纳通道策略(Keltner Channel)、唐奇安通道策略(Donchian)原理简介
本文介绍了三种金融量化分析中的通道突破策略:布林带策略(Bollinger Band)、肯特纳通道策略(Keltner Channel)和唐奇安通道策略(Donchian Channel),并提供了每种策略的原理和Python实现代码。
1927 2
|
敏捷开发 人工智能 安全
通义灵码+DeepSeek-R1:AI编程助手的新标杆?
通义灵码与DeepSeek-R1深度集成,重新定义AI编程工具边界。该组合通过大模型与垂直优化,提升代码生成、上下文理解及缺陷检测能力,显著提高开发者效率(节省35%编码时间)。适用于敏捷开发、系统重构等场景,尤其适合中小型研发团队和全栈开发者。
|
Java 开发工具 Spring
Spring的Factories机制介绍
Spring的Factories机制介绍
529 1
|
程序员
github登录+注册方法
github登录+注册方法
1003 0