玩转qsort——“C”

news/2024/5/15 15:52:19/文章来源:https://blog.csdn.net/weixin_74957752/article/details/129272380

各位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就到这里啦,这篇博客难度很大,确实花了小雅兰很多时间,未来还要继续加油呀!!!

 

 

 

 

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

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

相关文章

java异常分类和finally代码块中return语句的影响

首先看一下java中异常相关类的继承关系&#xff1a; 引用 1、分类 异常可以分为受查异常和非受查异常&#xff0c;Error和RuntimeException及其所有的子类都是非受查异常&#xff0c;其他的是受查异常。 两者的区别主要在&#xff1a; 受检的异常是由编译器&#xff08;编译…

小家电品牌私域增长解决方案来了

小家电品牌的私域优势 01、行业线上化发展程度高 相对于大家电动辄上千上万元的价格&#xff0c;小家电的客单价较低。而且与大家电偏刚需属性不同的是&#xff0c;小家电的消费需求侧重场景化&#xff0c;用户希望通过购买小家电来提高自身的生活品质。这就决定了用户的决策…

工作中责任链模式用法及其使用场景?

前言 笔者是金融保险行业&#xff0c;有这么一种场景&#xff0c;业务员录完单后提交核保&#xff0c;这时候系统会对保单数据进行校验&#xff0c;如不允许手续费超限校验&#xff0c;客户真实性校验、费率限额校验等等&#xff0c;当校验一多时&#xff0c;维护起来特别麻烦…

预览版Edge申请微软new Bing失败解决方案

文章目录1.首先需要配置科学上网2.下载预览版Edge浏览器卡它bug&#xff01;卡它bug&#xff01;卡它bug&#xff01;没有申请上ChatGPT的朋友们&#xff0c;试试new Bing吧&#xff0c;更新更强大&#xff0c;关于申请方式&#xff0c;网上已经有很多帖子了&#xff0c;其中一…

软件自动化测试工程师面试题集锦

以下是部分面试题目和我的个人回答&#xff0c;回答比较简略&#xff0c;仅供参考。不对之处请指出 1.自我介绍 答&#xff1a;姓名&#xff0c;学历专业&#xff0c;技能&#xff0c;近期工作经历等&#xff0c;可以引导到最擅长的点&#xff0c;比如说代码或者项目 参考&a…

SpringBoot入门 - SpringBoot HelloWorld

我们了解了SpringBoot和SpringFramework的关系之后&#xff0c;我们可以开始创建一个Hello World级别的项目了。创建 SpringBoot Web 应用为快速进行开发&#xff0c;推荐你使用IDEA这类开发工具&#xff0c;它将大大提升你学习和开发的效率。选择 Spring InitializeSpring提供…

Spring 事务(编程式事务、声明式事务@Transactional、事务隔离级别、事务传播机制)

文章目录1. 事务的定义2. Spring 中事务的实现2.1 MySQL 中使用事务2.2 Spring 中编程式事务的实现2.3 Spring 中声明式事务2.3.1 声明式事务的实现 Transactional2.3.2 Transactional 作用域2.3.3Transactional 参数设置2.3.4 Transactional 异常情况2.3.5 Transactional 工作…

一文读懂PaddleSpeech中英混合语音识别技术

语音识别技术能够让计算机理解人类的语音&#xff0c;从而支持多种语音交互的场景&#xff0c;如手机应用、人车协同、机器人对话、语音转写等。然而&#xff0c;在这些场景中&#xff0c;语音识别的输入并不总是单一的语言&#xff0c;有时会出现多语言混合的情况。例如&#…

ClickHouse进阶篇-多表连接物化视图

简介 在写这篇文章的时候doris 1.2 的物化视图只是支持单表建立物化视图&#xff0c;现在说下ClickHouse多表的物化视图。 前言 本文翻译自 Altinity 针对 ClickHouse 的系列技术文章。面向联机分析处理&#xff08;OLAP&#xff09;的开源分析引擎 ClickHouse&#xff0c;因…

全面了解 B 端产品设计 — 基础扫盲篇

在今天,互联网的影响力与作用与日俱增,除了我们日常生活领域的改变以外,对于商业领域的渗透也见效颇丰。 越来越多的企业开始使用数字化的解决方案来助力企业发展,包括日常管理、运营、统计等等。或者通过互联网的方式开发出新的业务形态,进行产业升级,如这几年风头正劲的…

ReentrantLock详说

目录 尝试加锁 如果加锁不成功 重点 尝试加锁 最外层lock方法 ReentrantLock.class public void lock() {sync.lock();} 进来发现是个抽象方法 abstract static class Sync extends AbstractQueuedSynchronizer abstract void lock(); 底下有两个实现类&#xff0c;一个…

Zookeeper3.5.7版本——Zookeeper的概述、工作机制、特点、数据结构及应用场景

目录一、Zookeeper的概述二、Zookeeper的工作机制三、Zookeeper的特点四、Zookeeper的数据结构五、Zookeeper的应用场景5.1、统一命名服务5.2、统一配置管理5.3、统一集群管理5.4、服务器动态上下线5.5、软负载均衡一、Zookeeper的概述 Zookeeper 是一个开源的分布式的&#x…

39万字完整版智能矿山项目建设整体解决方案

本资料来源网络&#xff0c;仅做知识分享&#xff0c;请勿商用。完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 1.1 总体技术要求 1.1.1 核心业务架构 智能矿山业务架构是在统一的标准与规范及安全运维保障体系下&#xff0c;按分层设计模式&#xff0c;分为设备层、…

【基于机器学习的推荐系统项目实战-1】初识推荐系统

本文目录一、为什么我们需要推荐系统&#xff1f;二、推荐系统的发展阶段三、推荐系统模型四、通用推荐系统框架4.1 数据生产4.2 数据存储4.3 算法召回4.4 结果排序4.5 结果应用4.6 新浪微博的框架开源结构图五、推荐常用特征5.1 用户特征5.2 物品特征六、推荐常用算法七、结果…

【自动化测试】一位自动化测试工程师居然不会封装框架?神秘自动化测试框架......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 自动化测试框架 自…

山寨APP频出?安全工程师和黑灰产在较量

在山寨这个领域&#xff0c;没有人比黑灰产更懂模仿。 据安全从业者介绍&#xff0c;一般而言&#xff0c;对于成熟的山寨开发者来说&#xff0c;几天时间内就可以做出一套前端框架。服务器、源代码、域名、服务商这些内容的创建&#xff0c;通过网上租赁的方式就可以解决。 比…

小红书“复刻”微信,微信“内造”小红书

配图来自Canva可画 随着互联网增长红利逐渐见顶&#xff0c;各大互联网平台对流量的争夺变得愈发激烈。而为了寻找新的业务可能性&#xff0c;各家都在不遗余力地拓宽自身边界。在此背景下&#xff0c;目前最为“吸睛”和“吸金”的社交、电商、种草、短视频等领域&#xff0c…

Qt音视频开发19-vlc内核各种事件通知

一、前言 对于使用第三方的sdk库做开发&#xff0c;除了基本的操作函数接口外&#xff0c;还希望通过事件机制拿到消息通知&#xff0c;比如当前播放进度、音量值变化、静音变化、文件长度、播放结束等&#xff0c;有了这些才是完整的播放功能&#xff0c;在vlc中要拿到各种事…

【vulhub漏洞复现】CVE-2018-2894 Weblogic任意文件上传漏洞

一、漏洞详情影响版本weblogic 10.3.6.0、weblogic 12.1.3.0、weblogic 12.2.1.2、weblogic 12.2.1.3WebLogic是美国Oracle公司出品的一个application server&#xff0c;确切的说是一个基于JAVAEE架构的中间件&#xff0c;WebLogic是用于开发、集成、部署和管理大型分布式Web应…

快速吃透π型滤波电路-LC-RC滤波器

π型滤波器简介 π型滤波器包括两个电容器和一个电感器&#xff0c;它的输入和输出都呈低阻抗。π型滤波有RC和LC两种&#xff0c; 在输出电流不大的情况下用RC&#xff0c;R的取值不能太大&#xff0c;一般几个至几十欧姆&#xff0c;其优点是成本低。其缺点是电阻要消耗一些…