玩转qsort——“C”
各位CSDN的uu们你们好呀,今天小雅兰的内容还是我们的深度剖析指针呀,上篇博客我们学习了回调函数这个知识点,但是没有写完,因为:小雅兰觉得qsort值得单独写出来!!!好啦,就让我们进入指针的世界吧
qsort是一个库函数,是用来排序的库函数,使用的是快速排序的方法
quicksort
我们先来复习一下之前所学习过的一种算法——冒泡排序
冒泡排序——“C”_认真学习的小雅兰.的博客-CSDN博客
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{int i = 0;for (i = 0; i < sz - 1; i++){//一趟冒泡排序的过程int j = 0;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;}}}
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };//排序//使用冒泡排序的算法,来排序int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz);//打印print_arr(arr, sz);return 0;
}

但是,这个算法最大的缺点就是只能排序整型,如果未来要排序浮点数呢?如果未来要排序一些字符串呢?结构体呢?那么,这个函数就搞不定了,仅仅能排序固定类型的数据
qsort的好处:
- 现成的
- 可以排序任意类型的数据
void qsort( void *base,//指向了待排序数组的第一个元素
size_t num,//待排序的元素个数
size_t width,//每个元素的大小,单位是字节
int (__cdecl *compare )(const void *elem1, const void *elem2 )
//函数指针
//指向一个函数,这个函数可以比较两个元素的大小
);
qsort是可以排序任意类型的数据的
- 比较两个整数的大小,> < =
- 比较两个字符串,strcmp
- 比较两个结构体数据(学生:张三、李四),指定比较的标准,拿什么比较?
int a=10;
void * p=&a;
//void * ——无具体类型的指针,所以它可以接收任何类型的地址
//*p;//err void*的指针不能使用解引用操作符
//p++;//err
下面,我们来使用一下qsort函数:

#include<stdio.h>
#include<stdlib.h>
//qsort函数的使用者提供这个函数
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}
test1()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);//使用qsort来排序整型数组,这里就要提供一个比较函数,这个比较函数能够比较2个整数的大小//qsort默认是排成升序的qsort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz);
}
int main()
{test1();return 0;
}

qsort这个库函数是不是很神奇呢?下面还有更加神奇的!!!
我们来测试一下qsort排序结构体数据
#include<stdio.h>
#include<stdlib.h>
//qsort函数的使用者提供这个函数
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
struct Stu
{char name[20];int age;
};
int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void print(struct Stu* ps, int sz)
{int i = 0;for (i = 0; i < 3; i++){printf("%d\n", ps[i].age);}
}
void test2()
{struct Stu s[] = { {"zhangsan",30},{"lisi",25 }, { "wangwu",50 } };int sz = sizeof(s) / sizeof(s[0]);//测试按照年龄来排序qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);print(s, sz);
}
int main()
{test2();return 0;
}

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{char name[20];int age;
};
int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void print(struct Stu *ps, int sz)
{int i = 0;for (i = 0; i < 3; i++){printf("%s\n", ps[i].name);}
}
void test2()
{struct Stu s[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };int sz = sizeof(s) / sizeof(s[0]);//测试按照名字来排序qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);print(s, sz);
}
int main()
{test2();return 0;
}

qsort底层是快速排序,但是小雅兰还没有学习快速排序的思想,所以暂时还不能之间实现qsort,所以使用冒泡排序的思想来实现一个类似于qsort这个功能的冒泡排序函数bubble_sort
使用回调函数,模拟实现qsort(采用冒泡的方式)。
测试函数:
void test3() {int arr[] = { 3,1,5,2,4,9,8,6,7,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz); }主函数:
int main() {test3();return 0; }模拟实现的bubble_sort()函数:
//假设排序为升序 //希望这个bubble_sort函数可以排序任意类型的数据 void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2)) {//base 待排序数组的第一个元素//元素个数和元素个数的大小不可能是负数,所以是size_t类型//函数指针//要确定趟数size_t i = 0;for (i = 0; i < num - 1; i++){//一趟冒泡排序的过程size_t j = 0;int flag = 1;//假设已经有序了//标记变量for (j = 0; j < num - 1 - i ; j++){//两个相邻的元素比较//arr[j] arr[j+1]if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//强制类型转换为char*//因为base为void类型,不能之间进行加减乘除,所以强制类型转换,但是又不能转换为int*,因为不一定就排序整型数组flag = 0;//交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}if (flag == 1){break;}} }在bubble_sort()函数中,调用了自定义的函数Swap,是用来交换元素的:
int cmp_int(const void* p1, const void* p2)//不知道要排序什么类型的数组,所以用void* {return *(int*)p1 - *(int*)p2; } void Swap(char* buf1, char* buf2,int width) {int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;} }打印函数:
void print_arr(int arr[], int sz) {int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n"); }
完整代码如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int cmp_int(const void* p1, const void* p2)//不知道要排序什么类型的数组,所以用void*
{return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1, char* buf2,int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2))
{//base 待排序数组的第一个元素//元素个数和元素个数的大小不可能是负数,所以是size_t类型//函数指针//要确定趟数size_t i = 0;for (i = 0; i < num - 1; i++){//一趟冒泡排序的过程size_t j = 0;int flag = 1;//假设已经有序了//标记变量for (j = 0; j < num - 1 - i ; j++){//两个相邻的元素比较//arr[j] arr[j+1]if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//强制类型转换为char*//因为base为void类型,不能之间进行加减乘除,所以强制类型转换,但是又不能转换为int*,因为不一定就排序整型数组flag = 0;//交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}if (flag == 1){break;}}
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}
void test3()
{int arr[] = { 3,1,5,2,4,9,8,6,7,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz);
}
int main()
{test3();return 0;
}

好啦,小雅兰玩转的qsort就到这里啦,这篇博客难度很大,确实花了小雅兰很多时间,未来还要继续加油呀!!!

相关文章:
玩转qsort——“C”
各位CSDN的uu们你们好呀,今天小雅兰的内容还是我们的深度剖析指针呀,上篇博客我们学习了回调函数这个知识点,但是没有写完,因为:小雅兰觉得qsort值得单独写出来!!!好啦,就…...
【干货】又是一年跳槽季!Nginx 10道核心面试题及解析
Nginx是一款轻量级的高性能Web服务器和反向代理服务器,由俄罗斯的Igor Sysoev开发。它具有占用资源少、高并发、稳定性高等优点,被广泛应用于互联网领域。在Nginx的面试过程中,面试官通常会提出一些核心问题,本文将介绍一些常见的…...
【线程安全的HashMap有哪些,CurrentHashMap底层是怎么实现线程安全的】
在 Java 中,线程安全的 HashMap 通常有以下几种实现: Collections.synchronizedMap 方法:该方法可以将 HashMap 转换为线程安全的 Map。 Hashtable 类:Hashtable 是一种线程安全的集合类,它与 HashMap 类似࿰…...
C语言-结构体【详解】
一、 结构体的基础知识 结构是一些值的集合,这些值称为成员变量结构的每个成员可以是不同类型的变量 (1)结构体的声明 写法一: 注: 括号后边的分号不能忘结构体末尾可以不创建变量,在主函数中再创建 struc…...
浏览器输入url到页面渲染完成经历了哪些步骤
一、URL解析 这一步比较容易理解,在浏览器地址栏输入url后,浏览器会判断这个url的合法性 ,以及是否有可用缓存,如果判断是 url 则进行域名解析,如果不是 url ,则直接使用搜索引擎搜索 二、域名解析 输入…...
大数据技术之Hadoop(Yarn)
第1章Yarn资源调度器思考:1)如何管理集群资源?2)如何给任务合理分配资源?Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等…...
5.建造者模式
目录 简介 四个角色 应用场景 实现步骤 和工厂模式的区别 简介 建造者模式也叫生成器模式,是一种对象构建模式;它可以把复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象;…...
数据库基础-数据库基本概念(1-1)
你好,欢迎来到数据库基础系列专栏,欢迎留言互动哦~ 目录一、数据库基础1. 数据库基本概念1.1 数据库1.2 什么是数据库管理软件1.3 表1.4 行1.5 列和数据类型1.6 主键1.7 什么是 SQL一、数据库基础 1. 数据库基本概念 1.1 数据库 数据库是一个以某种有…...
学习笔记-架构的演进之服务容错策略-服务发现-3月day01
文章目录前言服务容错容错策略附前言 “容错性设计”(Design for Failure)是微服务的一个核心原则。 使用微服务架构,拆分出的服务越来越多,也逐渐导致以下问题: 某一个服务的崩溃,会导致所有用到这个服务…...
采编式AIGC视频生产流程编排实践
作者 | 百度人工智能创作团队 导读 本文从业务出发,系统介绍了采编式 TTV的实现逻辑和实现路径。结合业务拆解,实现了一个轻量级服务编排引擎,有效实现业务诉求、高效支持业务扩展。 全文6451字,预计阅读时间17分钟。 01 背景 近…...
Leetcode23. 合并k个升序链表
一、题目描述: 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入:lists [[1,4,5],[1,3,4],[2,6]]输出:[1,1,2,3,4,4,5,6]解释&#…...
从用户出发,互联网产品策划方法论
【一】从用户到需求 产品经理需要具备两个非常重要的技能,一个叫策划,一个叫感知用户。 我们在分析问题的时候往往会说“这么做,我认为用户会怎么怎么样”、“用户会认为这样很不爽”,当我们这样说时,很有可能是把自己当成了用户,用某些特定的情感或记忆代表了用户。 当我…...
STM32 E18-D80NK红外检测
本文代码使用 HAL 库。 文章目录前言一、E18-D80NK 红外传感器:1. E18-D80NK 的介绍2. 电器特性二、红外检测小实验代码讲解三、实验现象总结前言 这篇文章介绍 如何使用 STM32 控制 E18-D80NK 进行红外检测。 一、E18-D80NK 红外传感器: 1. E18-D80N…...
Linux常用命令--进程和计划任务管理
一、程序和进程的关系 1、程序 ①保存在硬盘、光盘等介质中的可执行代码和数据 ②静态保存的代码 2、进程 ①在cpu及内存中运行及进程代码 ②动态执行的代码 ③父(fork)、子进程,每个程序可以创建一个或多个进程 父进程和子进程的区别&am…...
Unity TextMeshPro
Unity TextMeshPro 简介 TextMeshPro(也简称为TMP)号称是Unity的终极文本解决方案,它是Unity 的 UI 文本和旧版文本网格体的完美替代品。 功能强大且易于使用,使用高级文本渲染技术以及一组自定义着色器;提供实质性的视觉质量改进,同时在文本样式和纹理方面为用户提供令人…...
虹科分享| 浅谈HK-Edgility边缘计算平台
上周,我们推出了虹科新品HK-Edgility边缘计算平台以及uCPE解决方案。本篇文章我们再来谈一谈到底什么是边缘计算?为什么需要边缘计算?边缘计算和云计算有什么关系?HK-Edgility边缘计算平台将为您带来什么?一、边缘计算…...
React Router v6详解
旧版本React Router使用方式 BrowserRouter:通过 history 库,传递 history 对象,location 对象Switch:匹配唯一的路由 Route,展示正确的路由组件Route:视图承载容器,控制渲染 UI 组件 新版本R…...
帮助100w人成功入职的软件测试面试常见问题以及答案
测试面试题怎么来设计测试方案根据测试需求(包括功能需求和非功能性需求),识别测试要点,识别测试环境要求,安排测试轮次,根据项目计划和开发计划做整体的测试安排。被测试的特性:通过对需求规格…...
tensorflow2.4--2.回归问题分析
文章目录前言流程案例操作前言 流程 回归问题预测连续值,在某个区间内变动. 常见的线性回归问题模型是yaxb,然而现实世界由于大量的数据偏差以及复杂度,同时还有大量的噪声,往往达不到如此的精确解,实际解决问题时需要考虑噪声的存在 对于噪声,往往我们已经假设了它符合高斯…...
【2023】DevOps、SRE、运维开发面试宝典之Kafka相关面试题
文章目录 1、消息队列的流派2、kafka的优势3、Kafka与Zookeeper的关系4、Kafka消息队列各组件概念5、Kafka消息队列应用场景6、Kafka消息收发的过程7、Kafka消息数据存储概念8、kafka消息的偏移量概念原理9、Kafka消息数据的顺序消费概念原理10、Kafka单播消费消息的原理11、Ka…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
