当前位置: 首页 > news >正文

玩转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是可以排序任意类型的数据的

  1. 比较两个整数的大小,>  <  =
  2. 比较两个字符串,strcmp
  3. 比较两个结构体数据(学生:张三、李四),指定比较的标准,拿什么比较? 

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们你们好呀&#xff0c;今天小雅兰的内容还是我们的深度剖析指针呀&#xff0c;上篇博客我们学习了回调函数这个知识点&#xff0c;但是没有写完&#xff0c;因为&#xff1a;小雅兰觉得qsort值得单独写出来&#xff01;&#xff01;&#xff01;好啦&#xff0c;就…...

【干货】又是一年跳槽季!Nginx 10道核心面试题及解析

Nginx是一款轻量级的高性能Web服务器和反向代理服务器&#xff0c;由俄罗斯的Igor Sysoev开发。它具有占用资源少、高并发、稳定性高等优点&#xff0c;被广泛应用于互联网领域。在Nginx的面试过程中&#xff0c;面试官通常会提出一些核心问题&#xff0c;本文将介绍一些常见的…...

【线程安全的HashMap有哪些,CurrentHashMap底层是怎么实现线程安全的】

在 Java 中&#xff0c;线程安全的 HashMap 通常有以下几种实现&#xff1a; Collections.synchronizedMap 方法&#xff1a;该方法可以将 HashMap 转换为线程安全的 Map。 Hashtable 类&#xff1a;Hashtable 是一种线程安全的集合类&#xff0c;它与 HashMap 类似&#xff0…...

C语言-结构体【详解】

一、 结构体的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量结构的每个成员可以是不同类型的变量 &#xff08;1&#xff09;结构体的声明 写法一&#xff1a; 注&#xff1a; 括号后边的分号不能忘结构体末尾可以不创建变量&#xff0c;在主函数中再创建 struc…...

浏览器输入url到页面渲染完成经历了哪些步骤

一、URL解析 这一步比较容易理解&#xff0c;在浏览器地址栏输入url后&#xff0c;浏览器会判断这个url的合法性 &#xff0c;以及是否有可用缓存&#xff0c;如果判断是 url 则进行域名解析&#xff0c;如果不是 url &#xff0c;则直接使用搜索引擎搜索 二、域名解析 输入…...

大数据技术之Hadoop(Yarn)

第1章Yarn资源调度器思考&#xff1a;1&#xff09;如何管理集群资源&#xff1f;2&#xff09;如何给任务合理分配资源&#xff1f;Yarn是一个资源调度平台&#xff0c;负责为运算程序提供服务器运算资源&#xff0c;相当于一个分布式的操作系统平台&#xff0c;而MapReduce等…...

5.建造者模式

目录 简介 四个角色 应用场景 实现步骤 和工厂模式的区别 简介 建造者模式也叫生成器模式&#xff0c;是一种对象构建模式&#xff1b;它可以把复杂对象的建造过程抽象出来(抽象类别)&#xff0c;使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象&#xff1b;…...

数据库基础-数据库基本概念(1-1)

你好&#xff0c;欢迎来到数据库基础系列专栏&#xff0c;欢迎留言互动哦~ 目录一、数据库基础1. 数据库基本概念1.1 数据库1.2 什么是数据库管理软件1.3 表1.4 行1.5 列和数据类型1.6 主键1.7 什么是 SQL一、数据库基础 1. 数据库基本概念 1.1 数据库 数据库是一个以某种有…...

学习笔记-架构的演进之服务容错策略-服务发现-3月day01

文章目录前言服务容错容错策略附前言 “容错性设计”&#xff08;Design for Failure&#xff09;是微服务的一个核心原则。 使用微服务架构&#xff0c;拆分出的服务越来越多&#xff0c;也逐渐导致以下问题&#xff1a; 某一个服务的崩溃&#xff0c;会导致所有用到这个服务…...

采编式AIGC视频生产流程编排实践

作者 | 百度人工智能创作团队 导读 本文从业务出发&#xff0c;系统介绍了采编式 TTV的实现逻辑和实现路径。结合业务拆解&#xff0c;实现了一个轻量级服务编排引擎&#xff0c;有效实现业务诉求、高效支持业务扩展。 全文6451字&#xff0c;预计阅读时间17分钟。 01 背景 近…...

Leetcode23. 合并k个升序链表

一、题目描述&#xff1a; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]]输出&#xff1a;[1,1,2,3,4,4,5,6]解释&#…...

从用户出发,互联网产品策划方法论

【一】从用户到需求 产品经理需要具备两个非常重要的技能,一个叫策划,一个叫感知用户。 我们在分析问题的时候往往会说“这么做,我认为用户会怎么怎么样”、“用户会认为这样很不爽”,当我们这样说时,很有可能是把自己当成了用户,用某些特定的情感或记忆代表了用户。 当我…...

STM32 E18-D80NK红外检测

本文代码使用 HAL 库。 文章目录前言一、E18-D80NK 红外传感器&#xff1a;1. E18-D80NK 的介绍2. 电器特性二、红外检测小实验代码讲解三、实验现象总结前言 这篇文章介绍 如何使用 STM32 控制 E18-D80NK 进行红外检测。 一、E18-D80NK 红外传感器&#xff1a; 1. E18-D80N…...

Linux常用命令--进程和计划任务管理

一、程序和进程的关系 1、程序 ①保存在硬盘、光盘等介质中的可执行代码和数据 ②静态保存的代码 2、进程 ①在cpu及内存中运行及进程代码 ②动态执行的代码 ③父&#xff08;fork&#xff09;、子进程&#xff0c;每个程序可以创建一个或多个进程 父进程和子进程的区别&am…...

Unity TextMeshPro

Unity TextMeshPro 简介 TextMeshPro(也简称为TMP)号称是Unity的终极文本解决方案,它是Unity 的 UI 文本和旧版文本网格体的完美替代品。 功能强大且易于使用,使用高级文本渲染技术以及一组自定义着色器;提供实质性的视觉质量改进,同时在文本样式和纹理方面为用户提供令人…...

虹科分享| 浅谈HK-Edgility边缘计算平台

上周&#xff0c;我们推出了虹科新品HK-Edgility边缘计算平台以及uCPE解决方案。本篇文章我们再来谈一谈到底什么是边缘计算&#xff1f;为什么需要边缘计算&#xff1f;边缘计算和云计算有什么关系&#xff1f;HK-Edgility边缘计算平台将为您带来什么&#xff1f;一、边缘计算…...

React Router v6详解

旧版本React Router使用方式 BrowserRouter&#xff1a;通过 history 库&#xff0c;传递 history 对象&#xff0c;location 对象Switch&#xff1a;匹配唯一的路由 Route&#xff0c;展示正确的路由组件Route&#xff1a;视图承载容器&#xff0c;控制渲染 UI 组件 新版本R…...

帮助100w人成功入职的软件测试面试常见问题以及答案

测试面试题怎么来设计测试方案根据测试需求&#xff08;包括功能需求和非功能性需求&#xff09;&#xff0c;识别测试要点&#xff0c;识别测试环境要求&#xff0c;安排测试轮次&#xff0c;根据项目计划和开发计划做整体的测试安排。被测试的特性&#xff1a;通过对需求规格…...

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…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...