C语言:深入浅出qsort方法,编写自己的qsort完成冒泡排序

目录

什么是qsort? 

函数原型

比较函数 compar

排序整型数组

排序结构体数组

根据成员字符排序

 strcmp函数

根据成员整型排序

自定义qsort实现冒泡排序 

qsort的实现原理 

具体步骤

快速排序示例代码: 


什么是qsort? 

qsort是 C 语言标准库<stdib.h>中的一个函数,用于对数组进行快速排序,如下 

  • base:指向需排序的数组指针(同数组首元素地址)
  • num:数组中的元素个数。
  • size:每个元素的大小(以字节为单位)。
  • compar:比较函数指针,用于定义排序顺序。

函数原型

void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *));

比较函数 compar

比较函数 compar 负责定义数组元素的排序顺序。它应该接受两个参数,每个参数的类型都是 const void *,并返回一个整型值。比较函数的返回值定义了元素之间的排序关系:

  • 如果返回值小于 0,则第一个参数应该排在第二个参数之前。
  • 如果返回值等于 0,则两个参数的相对位置不变。
  • 如果返回值大于 0,则第一个参数应该排在第二个参数之后。

排序整型数组

void是无具体类型的指针,可以接受任意类型的地址,但是不能解引用,也不能+-操作,因为它不知道自己有几个字节的权限

int a = 10;
void *pv = &a;

compare函数形参中:因为指针类型是void,不能解引用,需要强制类型转换为int再解引用(根据自己的数据类型来决定是int还是char还是结构体)

#include <stdio.h>
#include <stdlib.h>int compare(const void* a, const void* b) {return (*(int*)a - *(int*)b);
}int main() {int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};int size = sizeof(arr) / sizeof(arr[0]);qsort(arr, size, sizeof(int), compare);for (int i = 0; i < size; i++) {printf("%d ", arr[i]); // 1 1 2 3 3 4 5 5 5 6 9}return 0;
}

排序结构体数组

根据成员字符排序

struct Stu
{char name[20];int age;
};int cmp_struct_name(const void *e1, const void *e2)
{return strcmp(((struct Stu *)e1)->name, ((struct Stu *)e2)->name); // lisi、wangwu、zhangsan
}struct Stu s[] ={{"zhangsan", 22},{"lisi", 24},{"wangwu", 23}};
int struct_size = sizeof(s) / sizeof(s[0]);
qsort(s, struct_size, sizeof(s[0]), cmp_struct_name);

 strcmp函数

  • strcmp函数用于比较字符串大小 ——> ==0 >0 <0
  • strcmp() 函数比较字符串时会逐个字符地比较它们的 ASCII 码值,直到有字符不相同时才停止比较。
  • 如果其中一个字符串已经结束了,而另一个字符串还没有结束,那么这个字符串就被认为比另一个字符串更小。
  • 头文件<string.h>

根据成员整型排序

struct Stu
{char name[20];int age;
};int cmp_struct_age(const void *e1, const void *e2)
{/* 从小到大 */return ((struct Stu *)e1)->age - ((struct Stu *)e2)->age; // 22 23 24
}struct Stu s[] ={{"zhangsan", 22},{"lisi", 24},{"wangwu", 23}};
int struct_size = sizeof(s) / sizeof(s[0]);
qsort(s, struct_size, sizeof(s[0]), cmp_struct_age);

自定义qsort实现冒泡排序 

/* 最终交换字节 */
void Swap(char *buf1, char *buf2, int width)
{for (int i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void my_qsort(void *base, int sz, int width, int (*cmp)(const void *e1, const void *e2))
{for (int i = 0; i < sz - 1; i++){for (int j = 0; j < sz - 1 - i; j++){/**实参传进去的是待比较的元素的地址之所以用char类型指针转换,是因为最保险,什么类型指针能访问的字节大小都可以从最小字节1开始活动比如这里,数据是int类型,那么cmp的实参第一个是 0*4,第二是 1*4,即第一个int数的地址,第二个int数的地址*/if (cmp((char *)base + j * width, (char *)base + (j + 1) * width) > 0){Swap((char *)base + j * width, (char *)base + (j + 1) * width, width);}}}
}my_qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{printf("%d ", arr[i]); // 9 8 7 6 5 4 3 2 1 0
}

qsort的实现原理 

qsort方法,它使用了一种叫做快速排序(Quicksort)的算法。快速排序是一种分治的排序算法,其基本思想是选择一个基准值,然后将数组中小于基准值的元素放到基准值的左边,大于基准值的元素放到基准值的右边,最终使得基准值左边的所有元素都小于等于基准值,右边的所有元素都大于等于基准值。然后递归地对基准值两边的子数组进行排序,直到整个数组有序为止。

具体步骤

  1. 选择基准值:从数组中选择一个元素作为基准值(通常选择第一个或者中间的元素)。
  2. 分区过程:将数组中的元素重新排列,将小于或等于基准值的放在基准值的左边,大于基准值的放在右边。
  3. 递归排序:对基准值左右两个子数组分别递归执行上述步骤。

快速排序示例代码: 

void quicksort(int arr[], int low, int high) {if (low < high) {int pivot = partition(arr, low, high);quicksort(arr, low, pivot - 1);quicksort(arr, pivot + 1, high);}
}int partition(int arr[], int low, int high) {int pivot = arr[low];int i = low, j = high;while (i < j) {while (i < j && arr[j] >= pivot) {j--;}arr[i] = arr[j];while (i < j && arr[i] <= pivot) {i++;}arr[j] = arr[i];}arr[i] = pivot;return i;
}

在这个示例中,quicksort 函数进行了递归排序,partition 函数则负责进行分区操作。具体而言,partition 函数以第一个元素作为基准值,然后对数组进行分区操作,并返回新的基准值的位置。对两个子数组进行的递归排序最终能够完成整个数组的排序过程。

快速排序的时间复杂度为 O(n log n),这使得快速排序成为一种非常高效的排序算法。在最好情况下,快速排序的时间复杂度是 O(n log n),而在最坏情况下,时间复杂度为 O(n^2),但平均情况下时间复杂度依然是 O(n log n)。当然,这也取决于选择的基准值和数组的初始状态。

同时,快速排序是一种原地排序算法,它不需要额外的存储空间来存储临时数据,只需要对原始数组进行原地交换和重排列。

总结来说,快速排序通过选择基准值、分区和递归排序等步骤,能够高效地对数组进行排序,在平均情况下的时间复杂度为 O(n log n),适用于大多数场景下的排序需求。因此,qsort 函数使用的快速排序算法在实际应用中具有较高的效率和性能表现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/134917.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

geoserver发布同一字段的多值渲染

Geoserver之同一字段的多值渲染 有时候我们需要对一个shp的某一字段值中的不同值进行区分展示&#xff0c;但是一般的渲染都是按照统一图层展示的&#xff0c;因此为了更好的效果&#xff0c;我们选择使用uDig等工具处理。 文章目录 Geoserver之同一字段的多值渲染前言一共是分…

休眠和睡眠有哪些区别?如何让电脑一键休眠?

电脑中有休眠和睡眠&#xff0c;那么它们有什么区别呢&#xff1f;下面我们就通过本文来了解一下。 休眠和睡眠的区别 电脑在睡眠状态时&#xff0c;会切断内存之外的设备电源&#xff0c;电脑会进入睡眠状态&#xff0c;当再次唤醒电脑后&#xff0c;不会影响睡眠前保存好的工…

机器学习练习1

线性回归 数据集模型,第一列代表人口,第二列代表利润 此处的线性回归 与 常规的 y wx b 不同的是 将b换成了w的一部分 故需要在数据集x前面加个1, 求出b . 可以简化计算,只需要一个乘法就可以

网络安全入门必学内容

网络安全入门 必/学/内/容/ 随着时代的发展&#xff0c;经济、社会、生产、生活越来越依赖网络。而随着万物互联的物联网技术的兴起&#xff0c;线上线下已经打通&#xff0c;虚拟世界和现实世界的边界正变得模糊。这使得来自网络空间的攻击能够穿透虚拟世界的边界&#xff0…

vscode中 vue3+ts 项目的提示失效,volar插件失效问题解决方案

文章目录 前情提要bug回顾解决方案最后 前情提要 说起来很耻辱&#xff0c;从mac环境换到window环境&#xff0c;vscode的配置都是云端更新过来的&#xff0c;应该是一切正常才对&#xff0c;奇怪的是我的项目环境出现问题了&#xff0c;关于组件的ts和追踪都没有效果&#xff…

vscode设置pycharm中的项目路径和debug方法

真大佬在这 真大佬在这 必须给大佬star 命令行运行&#xff1a; export PYTHONPATH:pwd:/home/bennie/bennie/bennie_project/AI_Lab python main.py 当关闭此命令行时&#xff0c;临时路径会清除&#xff0c;可以将上述export的整条语句&#xff0c;加入~/.bashrc中 该命令中…

重磅发布 OpenAI 推出用户自定义版 ChatGPT

文章目录 重磅发布 OpenAI 推出用户自定义版 ChatGPT个人简介 重磅发布 OpenAI 推出用户自定义版 ChatGPT OpenAI 首届开发者大会 (OpenAI DevDay) 于北京时间 11 月 7 日凌晨 02:00 开始&#xff0c;大会上宣布了一系列平台更新。其中一个重要更新是用户可以创建他们自己的自定…

从零开始的C++(十四)

继承&#xff1a; 作用&#xff1a;减少重复代码&#xff0c;简化程序。 用法&#xff1a; class b&#xff1a;public a {//...b中成员 } 在如上代码中&#xff0c;b类以public的方式继承了a类。规定a类是父类、基类&#xff0c;b类是子类、派生类。 关于继承方式&#xf…

Qt::WindowFlags

Qt::WindowFlags 文章目录 Qt::WindowFlags摘要窗口&部件Qt::WindowFlags&WindowType窗口类型窗口提示 关键字&#xff1a; Qt、 Qt::WindowFlags、 Qt::WindowType、 关键字4、 关键字5 摘要 今天在公司解决自己的Bugs的时候&#xff0c;发现一个以前可以用的功…

在Kotlin中设置User-Agent以模拟搜索引擎爬虫

前言 随着双十一电商活动的临近&#xff0c;电商平台成为了狂欢的中心。对于商家和消费者来说&#xff0c;了解市场趋势和竞争对手的信息至关重要。在这个数字时代&#xff0c;爬虫技术成为了获取电商数据的有力工具之一。本文将以亚马逊为例&#xff0c;介绍如何使用Kotlin编…

软件测试面试题【2023最新合集】

收集了各大公司的面试经验&#xff0c;现整理出来&#xff0c;希望能给正在找工作的志同道合的小伙伴一些指引&#xff0c;本文会持续更新的哦。 1、 CPU 和 GPU的区别 一个是通用计算&#xff0c;一个是专用计算。 CPU主要负责操作系统和应用程序&#xff0c;GPU主要负责跟…

【BUG解决】服务器没报警但是应用接口崩了....

最近遇到一个突发问题&#xff1a;服务器没报警但是应用接口崩了… 为其他业务系统提供一个接口&#xff0c;平时好好的&#xff0c;突然就嚷嚷反馈说访问不了了&#xff0c;吓得我赶紧跳起来&#xff01; 正常情况下在系统崩溃前&#xff0c;我会收到很多系统报警&#xff0…

【AI编程】ai编程插件汇总iFlyCode、codegeex

1、iFlyCode 开发公司&#xff1a;讯飞 支持IDE: VS Code、IntelliJ IDEA、CLion、PyCharm、WebStorm 支持语言: Python、JavaScript、C、Java 下载地址&#xff1a;https://iflycode.xfyun.cn/ iFlyCode 快捷键列表&#xff1a;  Tab 采纳建议  Esc 拒绝建议  Alt\ 主动…

CSDN每日一题学习训练——Java版(对给定的两个日期之间的日期进行遍历、子集 II、填充每个节点的下一个右侧节点指针)

版本说明 当前版本号[20231107]。 版本修改说明20231107初版 目录 文章目录 版本说明目录对给定的两个日期之间的日期进行遍历题目解题思路代码思路参考代码 子集 II题目解题思路代码思路参考代码 填充每个节点的下一个右侧节点指针题目解题思路代码思路参考代码 对给定的两…

Flink架构

1、Apache Flink集群的核心架构&#xff1a; 1、client&#xff08;作业客户端&#xff09;&#xff1a;提交任务的地方叫做客户端 2、JobManager&#xff08;作业管理器&#xff09;&#xff1a;作用是用于管理集群中任务 3、TaskManager&#xff08;任务管理器&#xff09;&a…

WPF布局与控件分类

Refer&#xff1a;WPF从假入门到真的入门 - 知乎 (zhihu.com) Refer&#xff1a;WPF从假入门到真的入门 - 知乎 (zhihu.com) https://www.zhihu.com/column/c_1397867519101755392 https://blog.csdn.net/qq_44034384/article/details/106154954 https://www.cnblogs.com/mq0…

unittest 统计测试执行case总数,成功数量,失败数量,输出至文件,生成一个简易的html报告带饼图

这是一个Python的单元测试框架的示例代码&#xff0c;主要用于执行测试用例并生成测试报告。其中&#xff0c;通过unittest模块创建主测试类MainTestCase&#xff0c;并加载其他文件中的测试用例&#xff0c;统计用例的执行结果并将结果写入文件&#xff0c;最后生成一个简单的…

无人机航迹规划:五种最新智能优化算法(KOA、COA、LSO、GRO、LO)求解无人机路径规划MATLAB

一、五种算法&#xff08;KOA、COA、LSO、GRO、LO&#xff09;简介 1、开普勒优化算法KOA 开普勒优化算法&#xff08;Kepler optimization algorithm&#xff0c;KOA&#xff09;由Mohamed Abdel-Basset等人于2023年提出。五种最新优化算法&#xff08;SWO、ZOA、EVO、KOA、…

【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割10(测试推理篇)

对于直接将裁剪的patch&#xff0c;一个个的放到训练好的模型中进行预测&#xff0c;这部分代码可以直接参考前面的训练部分就行了。其实说白了&#xff0c;就是验证部分。不使用dataloader的方法&#xff0c;也只需要修改少部分代码即可。 但是&#xff0c;这种方法是不end t…

Intel oneAPI笔记(4)--jupyter官方文档(Unified Shared Memory)学习笔记

前言 本文是对jupyterlab中oneAPI_Essentials/03_Unified_Shared_Memory文档的学习记录&#xff0c;主要包含对统一共享内存的讲解 USM概述 USM (Unified Shared Memory)是SYCL中基于指针的内存管理。对于使用malloc或new来分配数据的C和C程序员来说应该很熟悉。当将现有的C…