qsort函数实现对任意数据的排序

2023-11-02

qsort介绍

qsort函数是一个库函数,它的作用是对数据进行排序,思想是:快速排序!

因为是库函数,所以在使用的时候需要引头文件:<stdlib.h>/<search.h>

我们可以通过以下的方式使用qsort函数:qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );
参数解释:
(void *)argv:你想要从哪个数组/结构体的哪个元素开始排序就将它的地址作为实参。

(size_t)argc:你想要排序的元素个数。

sizeof(char*):排序的元素大小;

compare:是一个函数指针,指向的函数是比较元素大小的,因为不同的数据的比较方法是不同的,所以在创建qsort函数的时候将比较方法抽离出来,需要我们编写。

假如我要使用qsort排序一个数组的全部元素,那么我在引用qsort的时候应该这么写:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int arr[] = {9,5,4,8,3,1,7,6,10,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组每个元素的大小
	qsort(arr, sz, sizeof(arr[0]), compare);

	return 0;
}


如果我只想排序5到7共6个元素的时候那我该这么写:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int arr[] = {9,5,4,8,3,1,7,6,10,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr+1, 6, sizeof(arr[0]), compare);

	return 0;
}


compare函数介绍

compare函数是qsort排序的核心

compare函数的定义形式: compare( const void* elem1, const void* elem2 )。

看到这里是不是感觉怪怪的?再引用compare函数的时候并没有参数啊,怎么这里有两个指针呢?我在接触到qsort的时候也有这样的疑问,于是我找到了qsort的函数原型:

static void __cdecl shortsort(char *lo, char *hi, size_t width,  
                                                          int (__cdecl *comp)(const void *, const void *));


static void __cdecl swap(char *p, char *q, size_t width);

可以看到compare确实是有两个指针的,至于elem1和elem2的地址是如何传进去的,博主也不太懂呢,需要去研究源码,但是我们知道它是把 (void *)argv的地址和 (void *)argv+1的地址传了过去,并且每次调用玩都会对地址进行加一操作,一直到(size_t)argc的地址为止,知道这些就足够我们使用qsort函数了。

在这里插入图片描述

从这张图片我们可以看到,当elem1指向的元素大于elem2指向的元素时compare函数会返回一个正值等于的时候会返回0小于的时候会返回负值,这对没深入理解compare函数的我们来说不知道返回正值、0、负值意味着什么,我们只需要记住这样的写法未来排序完成是升序的就行,如果想要降序加个负号或者交换两个指针的位置就可以了。

这里我想说一下void*指针,这个指针是一个万能指针,它可以接收任何类型的元素的地址,但是它也有美中不足的地方,那就是无法对这个指针进行任何的运算操作,像什么++,–,*等都是不行的,因为它没有类型,在进行这些操作时无法知道它该访问几个字节的内存,自然是无法进行操作。

不同的数据类型相应的比较函数定义

对数组元素为数字的:
int  compare(const void *e1,const void *e2)
{

	return  *(int*)e1 - *(int*)e2;//结果要返回正,0,负,那我干脆让它们相减。
}

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int arr[] = {9,5,4,8,3,1,7,6,10,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算元素个数
	qsort(arr, sz, sizeof(arr[0]), compare);
	int a = 0;
	for (a = 0; a < sz; a++)
	{
		printf("%d\n", arr[a]);
	}
	return 0;
}

在return的时候将e1和e2指针进行了强制类型转换,因为void的指针是不能解引用的,又因为数组元素是int,所以转为int。
如果是小数如下,double也一样:

int  compare(const void *e1,const void *e2)
{

	return  (int)(*(float*)e1 - *(float*)e2);//将指针强制转换为float*,将计算结果转为int
}

#include<stdio.h>
#include<stdlib.h>

int main()
{
	float arr[] = {9.22,9.21,8.99,8.21,0,8.89,10.2,7.8,6.3,10.1,2.1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), compare);
	int a = 0;
	for (a = 0; a < sz; a++)
	{
		printf("%f\n", arr[a]);
	}
	return 0;
}

数组元素为字符时比较函数定义:

在c语言中,字符和整数是相通的,所以它们的比较函数差不多:

int  compare(const void *e1,const void *e2)
{

	return  (int)(*(char*)e1 - *(char*)e2);
}


#include<stdlib.h>

int main()
{
	char arr[] = {'e','f','c','a','b'};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), compare);
	int a = 0;
	for (a = 0; a < sz; a++)
	{
		printf("%c\n", arr[a]);
	}
	return 0;
}
结构体数据比较函数定义:

结构体其实和数组一样:

struct stu//创建结构体变量
{
	char name[20] ;
	int age;
};
int compare(const void*e1, const void *e2)
{
	return  strcmp((*(((struct stu*)e1)->name) , *(((struct stu*)e2)->name)));//将指针强制转换为结构体指针
}


int main()
{
	struct stu s1[3] = { { { "zhangsan" },  20  }, { { "lisi" },  10  }, { { "abo" },  15  } };
	//s1是一个数组,数组有3个元素,每个元素都是一个结构体。
	int sz = sizeof(s1) / sizeof(s1[0]);
	qsort(s1, sz, sizeof(s1[0]), compare);
	int a = 0;
	for (a = 0; a < sz; a++)
	{
		printf("%s\n", (s1+a)->name);//打印结构体
	}
	return 0;
}

``

博主不才,如有错误请及时指出,如果有想深入了解qsort函数的朋友 点击链接  [qsort函数源码分析](https://blog.csdn.net/nuptxxp/article/details/6961030) 相信会找到你想要的。

加油csdn的小伙伴,让我们一起努力,向大厂前进!!!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

qsort函数实现对任意数据的排序 的相关文章

  • 超详细的OpenCV入门教程,12小时带你吃透OpenCV。

    OpenCV简介 OpenCV是一个基于Apache2 0许可 开源 发行的跨平台计算机视觉和机器学习软件库 可以运行在linux Windows Android和MAC OS操作系统上 1 它轻量级而且高效 由一系列 C 函数和少量 C
  • vue中scoped与/deep/深度选择器原理总结

    最近在写一个vue element ui项目 使用element ui某些组件修改样式时 老是需要加上 deep 深度选择器 以前只是知道这样用 但是还不清楚他的原理 这次就来好好的梳理一下 1 首先我们需要知道css中的属性选择器 w3c
  • Introduction to Causal Inference:Chapter 1因果推断概论

    本文是学习brady neal于2020年开设的因果推断课程Introduction to Causal Inference的记录 概述 本chapter主要分四个部分 辛普森悖论 为什么相关性不是因果关系 什么展示了因果关系 在观测性研究
  • 七、PyQt5实现Python界面设计_滑块控件(QSlider)与计数器控件(QSpinBox)

    目录 一 QSlider滑块控件 1 简介 2 常用函数 3 代码演示 二 QSpinBox计数器控件 1 简介 2 常用函数 3 代码演示 一 QSlider滑块控件 1 简介 1 水平或者垂直的滑动控件 一般用来设置数字 快速滑动来调整
  • 「第二篇」全国一等奖,经验帖。

    点击上方 大鱼机器人 选择 置顶 星标公众号 福利干货 第一时间送达 阅读文本大概需要 6 分钟 0 前言 本文作者 谢斌 曾经获得2017年控制题 板球控制系统 全国一等奖 他之前有写过几篇关于比赛的文章 大家可以点击阅读 全国一等奖 他

随机推荐

  • 如何使用html制作网页

    如何使用html制作网页 一 html简介 1 1概念 HTML即HyperText Mark up Language 意思是超文本标记语言 HTML不是一种编程语言 而是一种标记语言 超文本指的是超链接 标记指的是标签 是一种用来制作网页
  • 如何保护单例不被反射修改?

    public class Safety private static Safety instance new Safety private Safety if instance null throw new RuntimeException
  • hadoop生态系统的详细介绍-详细一点

    前提 日常喜欢看一些微信分享的好文 总结下来 可以作为过滤器吧 节约更多人的时间 在这里引用的是别人的文章 对原文的作者表示感谢 确实写的很好 hadoop生态系统的详细介绍 简介 Hadoop是一个开发和运行处理大规模数据的软件平台 是A
  • Kafka By the sea——kafka的使用场景

    文章目录 消息队列概述 消息队列应用场景 异步处理 应用解耦 流量削锋 日志处理 消息通讯 消息中间件示例 电商系统 日志收集系统 常用消息队列 ActiveMQ Kafka 消息队列概述 消息队列中间件是分布式系统中重要的组件 主要解决应
  • js怎么做延迟函数delay

    const delay ms gt new Promise resolve reject gt setTimeout resolve ms const getData status gt new Promise resolve reject
  • 评分算法_协同过滤推荐算法:评分预测准确性评估

    纸上得来终觉浅 绝知此事要躬行 宋 陆游 冬夜读书示子聿 对于评分预测常用的准确性评测指标是均方根误差RMSE和平均绝对误差MAE RMSE 均方根误差 对大的偏差更敏感 MAE 平均绝对值误差 注意 R 表示数据集合的长度 准确性指标计算
  • PADS Router VX2.7 操作界面以及常用设置

    打开方式 直接双击Router或者从layout中打开 打开Router 右击工具栏 选择自己想要使用的工具 项目浏览器 输出窗口 电子表格 导航窗口 都在右上角 标志工具栏中 如果不小心关掉 点击即可恢复 坐标以及单位 设置在 工具栏中的
  • 聊聊软件测试的那些事

    笔者入行软件测试行业也有两年左右的时间了 这两年中 在工作中也学习 积累了一些知识 但是每每谈及理论 又好像怎么也说不清一些东西的定义 其实很多人认为 知识学习了会用就可以 但软件测试的道路上 打好基础是很重要的 有些东西你知道但无法清晰表
  • 【leetcode每日刷题】214. 最短回文串

    给定一个字符串 s 你可以通过在字符串前面添加字符将其转换为回文串 找到并返回可以用这种方式转换的最短回文串 示例 1 输入 aacecaaa 输出 aaacecaaa 示例 2 输入 abcd 输出 dcbabcd 解法 KMP算法 假设
  • BUCK电路输入电容计算

    输入电容决定了输入电压的纹波 对于Buck变换器的输入端来说 输入电流是不连续的 在开关管导通的时候会有极大的阶跃电流 芯 片 BUCK控制器 时 间 2021 04 27 说 明 适用于稳态和动态负载 在Buck变换器的输入电压最小时 满
  • Qt中自定义结构体的使用

    Qt的自定义结构体Qt是不认识的 下面就直接列出使用方法 第一步 建议把所需的结构体放在一个单独头文件中 防止头文件相互包含 gg 而且还有条件编译的头自动生成 直接向工作添加C 头文件 自己把名字取好就行了 注意 这样会在 pro中 HE
  • 【JavaScript高级】内存管理与闭包:垃圾回收GC、闭包定义、访问和执行过程、内存泄漏

    文章目录 内存管理 垃圾回收GC 引用计数 Reference counting 标记清除 mark Sweep 闭包 定义 闭包的访问和执行过程 内存泄漏 浏览器的优化 参考 内存管理 所有编程语言 在代码的执行过程中都需要给它分配内存
  • 【python】多进程multiprocessing模块、进程池的使用

    multiprocessing中的多进程Process的基本使用 在python中 进程是通过 multiprocessing 多进程模块来管理的 multiprocessing模块提供了一个Process类来创建进程对象 创建子进程 Pr
  • 【使用 BERT 的问答系统】第 2 章 :用于自然语言处理的神经网络

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • linux脚本定时调用存储过程,LINUX定时执行SHELL脚本实现DB2对存储过程的调用

    需求分析 本地化零件待办数量对应用户统计存入数据表 定时更新 使用linux的crontab定时任务来完成 1 编写存储过程 设置指向的数据库 SET SCHEMA DB2INST1 设置当前的路径 SET CURRENT PATH SYS
  • Java概述

    文章目录 一 Java简介 1 1 Java版本 1 2 Java特点 二 Java运行机制 2 1 Java运行过程 2 2 JDK JRE JVM 三 Java开发环境 3 1 下载 安装JDK 3 2 配置环境变量 四 Java开发规
  • R语言实战-第八章回归

    第八章 回归 简单线性回归 用到基础包中的women数据集 研究身高与体重的关系 head women fit lt lm weight height data women summary fit fitted fit 列出拟合模型的预测值
  • 【深度学习】RetinaFace人脸检测简要介绍

    介绍 Insight Face在2019年提出的最新人脸检测模型 原模型使用了deformable convolution和dense regression loss 当时在 WiderFace 数据集上达到SOTA 基网络有三种结构 基于
  • Java使用base64格式上传图片

    使用蚂蚁金服ui直接返回的是base64格式的图片 通过post方式进行请求 然后在控制器中以字符串的形式进行接收 接收之后进行转图片存储处理 只保存路径到数据库中 base64字节转图片代码 package com utils impor
  • qsort函数实现对任意数据的排序

    学会使用qsort函数排序 qsort介绍 compare函数介绍 不同的数据类型相应的比较函数定义 对数组元素为数字的 数组元素为字符时比较函数定义 结构体数据比较函数定义 qsort介绍 qsort函数是一个库函数 它的作用是对数据进行