C语言进阶之冒泡排序

          

                              ✨ 猪巴戒:个人主页✨

               所属专栏:《C语言进阶》

        🎈跟着猪巴戒,一起学习C语言🎈

目录

前情回顾

1、回调函数

2、冒泡排序

3、库函数qsort

cmp(sqort中的比较函数,需要我们自定义)

整形的升序排列

整形的倒序排列

结构体的排序

结构体按照名字(char类型)排序

结构体按照年龄(int类型)排序

库函数qsort的模拟实现(bubble_sort)

呈现bubble_sort函数的整体代码:

 bubble_sort的结构体排序

age: 

name:


前情回顾

函数指针

我们有一个函数,为Add,我们将函数的地址用指针来存储,这个指针就叫做函数指针。

int Add(int x,int y)
{return x+y;
}int main()
{int (*pf)(int,int) = Add;//pf就是函数指针。return 0;
}

函数指针数组

把函数指针放在数组中,就是函数指针的数组。

int Add(int x,int y)
{return x+y;
}
int Sub(int x,int y)
{return x-y;
}
int Mul(int x,int y)
{return x*y;
}
int Div(int x,int y)
{return x/y;
}
int main()
{int (*arr[4])(int ,int) = {Add,Sub,Mul,Div};//这个就是函数指针数组。return 0;
}

0ef772519fa440768e39c8e8e92b995b.png

函数指针数组就可以调用函数:

int main()
{int i = 0;scanf("%d",&i);int ret = arr[i](8,4);printf("%d\n",ret);
}

1、回调函数

回调函数就是应该通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由这个函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

我们可以把Add函数称为回调函数。

int Add(int x,int y)
{return x+y;
}
int main()
{int (*pf)(int,int) = Add;int ret = pf(8,4);return 0;
}

2、冒泡排序

对一个数组进行升序排序。

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;}} }
}
int main()
{int arr[] = {9,8,7,6,5,4,3,2,1 };//把数组排成升序int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr,sz);int i = 0;for(i=0;i<sz;i++){printf("%d",arr[i]};}

这个冒泡排序不够高效,如果我们进行一趟冒泡排序,但是一个数字都没有交换,就说明这个数组已经排序好了,就不用继续排序了,

我们可以通过,在进行这一趟冒泡排序前设定int flag = 1;

如果数字进行了交换,就把flag的值改为0;

没有数字进行交换,那么flag的值还是1;

我们通过判断flag的值看数组是否已经排好序。

void bubble_sort(int arr[],int sz)
{int i=0;//趟数for(i=0;i<sz-1;i++){int flag = 1;//假设数组是排好序的。//一趟冒泡排序的过程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;flag = 0;//数组进行了排序}}  if(flag == 1){break;}    }}
int main()
{int arr[] = {9,8,7,6,5,4,3,2,1 };//把数组排成升序int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr,sz);int i = 0;for(i=0;i<sz;i++){printf("%d",arr[i]};}return 0;
}

3、库函数qsort

使用快速排序的思想实现的一个排序函数。

qsort可以排序任何类型的数据

void qsort(void* base,//你要排序的数据的起始位置size_t num,//待排序的数据元素的个数size_t width,//待排序的数据元素的大小(单位是字节)int(* cmp)(const void* e1,const void* e2)//函数指针-比较函数);

cmp(sqort中的比较函数,需要我们自定义)

int(* cmp)(const void* e1,const void* e2)中的e1,e2就是我们要比较数据的地址。

在这个比较函数中我们实现不同类型的元素比较

void*是无具体类型的指针,可以接收任何类型的地址

void*是无具体类型的指针,所以不能解引用操作,也不能+-整数

当比较函数返回的是大于0的数字,那么两组数据就会进行交换。

进行整型数据的比较, 这是进行升序排列

int cmp_int(const void* e1,const void* e2)
{return (*(int*)e1 - *(int*)e2);
}

整形的升序排列

通过qsort来将数组进行升序排序

//比较两个整形元素
//e1指向一个整形
//e2指向另外一个整形
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void* e1,const void* e2)
{return (*(int*)e1 - *(int*)e2);
}
int main()
{int arr[] = {9,8,7,6,5,4,3,2,1};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);int i = 0;for(i=0;i<sz;i++){printf("%d ",arr[i]);}    return 0;
}

cmp_int就是回调函数 

整形的倒序排列

当我们需要进行降序排列,只要将e2和e1的顺序倒过来就可以实现

int cmp_int(const void* e1,const void* e2)
{return (*(int*)e2 - *(int*)e1);
}

结构体的排序

结构体按照名字(char类型)排序

char类型的数据不能够直接比较,我们用到strcmp进行比较,

库函数strcmp

头文件<string.h>

int strcmp( const char *string1, const char *string2 );

如果string1小于string2,就会返回小于0的数

如果string1等于string2,就会返回0

如果string1大于string2,就会返回大于0的数

#include<stdlib.h>
#include<string.h>
struct Stu
{char name[20];int age;
};
int cmp_stu_by_name(const void* e1,const void* e2)
{return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
}
int main()
{struct Stu s[] = {{"zhangsan",15},{"lisi",30},{"wangwu",25}};int sz = sizeof(s) / sizeof(s[0]);qsort(s,sz,sizeof(s[0]),cmp_stu_by_name);return 0;
}

cmp_stu_by_name就是回调函数

结构体按照年龄(int类型)排序

#include<stdlib.h>
#include<string.h>
struct Stu
{char name[20];int age;
};
int cmp_stu_by_age(const void*e1,constvoid* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{struct Stu s[] = {{"zhangsan",15},{"lisi",30},{"wangwu",25}};int sz = sizeof(s) / sizeof(s[0]);qsort(s,sz,sizeof(s[0]),cmp_stu_by_age);return 0;
}

库函数qsort的模拟实现(bubble_sort)

如何实现qsort函数?库函数qsort的设计原理是什么?

创建自定义函数实现库函数qsort的功能。

基于qsort实现原理,实现将整形数组升序排列

设计自定义函数bubble_sort,等同于库函数qsort

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

base:数据的起始位置,首元素的地址

sz: 数据元素的个数,比较数组的话,就是数组中元素的个数

width:待排序的数据元素的大小(单位是字节),比较整形数组的话,就是4个字节,数组元素占内存的大小

cmp:自定义的比较函数。

 关于bubble_sort的设计细节

这是我们对解决整形数组升序排列问题,也就是冒泡排序,原来的的bubble_sort.

但是我们现在要设计的bubble_sort,需要与qsort有相同的功能(排序任何类型的数据)

void bubble_sort(int arr[],int sz)
{int i=0;//趟数for(i=0;i<sz-1;i++){int flag = 1;//假设数组是排好序的。//一趟冒泡排序的过程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;flag = 0;//数组进行了排序}}  if(flag == 1){break;}    }}

1.

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))

参数void类型可以接收任何类型的数据

2.

判断大小,

原来:数组元素比较大小

现在:比较一种无知类型元素大小,通过比较函数(cmp)来比较,由于我们不知道要比较的元素类型是什么,但是我们要找到每个元素的地址,就通过(char*)base + j * width,

第一个元素的地址就是首元素的地址,

第二个元素的地址就是首元素的地址加上一个元素的字节

width:待排序的数据元素的大小(单位是字节)

在bubble_sort中,cmp((char*)base + j * width, (char*)base + (j + 1) * width)

3.

自定义函数(cmp)的实现,已知我们要比较的是整形元素的大小,和库函数qsort解决整形的升序排列一样

int cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}

4.

交换元素

 cmp_int的功能

当比较函数返回的是大于0的数字,那么两组数据就会进行交换。

进行整型数据的比较, 这是进行升序排列

在bubble_sort中,当cmp判断>0时

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)

进行交换

交换函数

我们要找到各个元素我们才能进行比较,所以和cmp函数的实现类似,

我们要传递的参数

Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);

找到了各个元素的地址,也知道元素的大小(字节),就可以进行比较,

一个一个字节进行比较,

Swap函数实现:

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++;}
}

 5.

为了函数的高效性,我们把原来的flag的设计保留。

也就是int flag = 1;(假设数组已经排列好)

如果在这一趟的冒泡排序的过程中,数字进行了交换,就把flag的值改为0;

没有数字进行交换,那么flag的值还是1,就可以直接跳出循环;

呈现bubble_sort函数的整体代码:

#include<stdio.h>
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++;}
}
int cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{int i = 0;//趟数for (i = 0; i < sz - 1; i++){int flag = 1;//假设数组是排好序//一趟冒泡排序的过程int j = 0;for (j = 0; j < sz - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);flag = 0;}}if (flag == 1){break;}}
}
int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };//0 1 2 3 4 5 6 7 8 9//把数组排成升序int sz = sizeof(arr) / sizeof(arr[0]);//bubble_sort(arr, sz);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}

e12eca3b78924dceba38b973cb8aff85.png

 bubble_sort的结构体排序

前面有完整的bubble_sort的实现,这里就不把bubble_sort写上了

#include<string.h>
struct Stu 
{char name[20];int age;
};
int cmp_stu_by_age(const void* e1, const void* e2)
{ return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
void test()
{struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };int sz = sizeof(s) / sizeof(s[0]);bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);//bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
int main()
{test();return 0;
}

age: 

90d276b4d2b4434996091f6029b1cc47.png

name:

f364844a2fa2439c82aef0a529082e32.png

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

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

相关文章

STM32F4串口USART发送为00的解决方案

检查接线是否正确检查TX是否为复用推挽输出 3.检查是否将TX和RX引脚重映射为USART功能 在STM32中&#xff0c;每个GPIO引脚可以配置为不同的复用功能&#xff0c;例如UART、SPI、I2C等。具体来说&#xff0c;GPIO_PinAFConfig函数用于配置GPIO引脚的复用功能。它的参数包括GPIO…

2023年【四川省安全员A证】复审考试及四川省安全员A证考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 四川省安全员A证复审考试根据新四川省安全员A证考试大纲要求&#xff0c;安全生产模拟考试一点通将四川省安全员A证模拟考试试题进行汇编&#xff0c;组成一套四川省安全员A证全真模拟考试试题&#xff0c;学员可通过…

c++|引用

目录 一、引用概念 二、引用特性 三、常引用 &#xff08;具有常属性的引用变量&#xff09; 四、使用场景 一、引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;他和他引用的变量共用同…

Spring Cloud 简介

1、简介 Spring CloudLevel up your Java code and explore what Spring can do for you.https://spring.io/projects/spring-cloud Spring Cloud 是一系列有序框架的集合&#xff0c;其主要的设施有&#xff0c;服务发现与注册&#xff0c;配置中心&#xff0c;消息总…

计算机组成原理-主存储器与CPU的连接

文章目录 知识总览单块存储芯片与CPU的连接位扩展&#xff08;存储字的位数&#xff09;字扩展&#xff08;存储字数&#xff09;关于线选法和片选法字位同时扩展总结补充&#xff1a;译码器 知识总览 单块存储芯片与CPU的连接 数据总线&#xff0c;地址总线&#xff0c;片选线…

Postman插件如何安装(一)

我们chrome插件网热门推荐的软件之一就是postman。但是postman的适应平台分为&#xff1a;postman chrome应用程序&#xff0c;postman应用程序&#xff0c;postman插件。谷歌应用商店从2018年3月开始停止chrome应用程序的更新。除非继续使用老版本的postman chrome应用程序&am…

【代码随想录】刷题笔记Day33

前言 Day33虽说是一个月&#xff0c;但是从第一篇开始实际上已经过了8个月了&#xff0c;得抓紧啊 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 前面组合就强调过差别了&#xff0c;这道题是排序&#xff0c;因此每次要从头到尾扫&#xff0c;结合used数组 class So…

数字IC基础:有符号数和无符号数的加减运算

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 首先说明&#xff0c;本篇文章并不涉及补码运算正确性的证明&#xff0c;仅是对补码运算在有符号数和无符号数中运行进行讨论。 补码运算最大的作用在于消除计算机…

机器学习8:在病马数据集上进行算法比较(ROC曲线与AUC)

ROC曲线与AUC。使用不同的迭代次数&#xff08;基模型数量&#xff09;进行 Adaboost 模型训练&#xff0c;并记录每个模型的真阳性率和假阳性率&#xff0c;并绘制每个模型对应的 ROC 曲线&#xff0c;比较模型性能&#xff0c;输出 AUC 值最高的模型的迭代次数和 ROC 曲线。 …

5 个适用于 Linux 的开源日志监控和管理工具

当Linux等操作系统运行时&#xff0c;会发生许多事件和在后台运行的进程&#xff0c;以实现系统资源的高效可靠的使用。这些事件可能发生在系统软件中&#xff0c;例如 init 或 systemd 进程或用户应用程序&#xff0c;例如 Apache、MySQL、FTP 等。 为了了解系统和不同应用程序…

UE5和UE4版本更新重大改变汇总。

转载&#xff1a;UE5和UE4版本更新重大改变汇总。 - 知乎 (zhihu.com) 用户界面变化&#xff1a; 1&#xff0c;原先拖动给放置Actor的place actors&#xff0c;世界大纲&#xff0c;Level等都可以通过右击隐藏到侧边栏&#xff1b; 2&#xff0c;Command命令窗口和ContentBr…

优秀智慧园区案例 - 佛山美的工业城零碳智慧园区,先进智慧园区建设方案经验

一、项目背景 美的工业园区西区最早建于上世纪90年代&#xff0c;到现在已经过去近30年&#xff0c;而这三十年恰恰是信息科技大发展的30年&#xff0c;原有的生产办公条件已不能很好的承载新时期办公和参观接待的需求。所以在21年美的楼宇科技事业部决定对原来的园区进行改造…

文本转语音

免费工具 音视频转译 通义听悟 | https://tingwu.aliyun.com/u/wg57n33kml5nkr3p 音色迁移 speechify | https://speechify.com/voice-cloning/ 视频生成 lalamu | http://lalamu.studio/demo/ 画质增强 topazlabs video AI | https://www.topazlabs.com 付费工具 rask | htt…

LeetCode热题100——动态规划

动态规划 1. 爬楼梯2. 杨辉三角3. 打家劫舍 1. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; // 题解&#xff1a;每次都有两种选择&#xff0c;1或者2 int climbStairs(int n) {if (n …

STM32CubeMX学习笔记-CAN接口使用

STM32CubeMX学习笔记-CAN接口使用 CAN总线传输协议1.CAN 总线传输特点2.位时序和波特率3.帧的种类4.标准格式数据帧和遥控帧从STM32F407参考手册中可以看出主要特性如下CAN模块基本控制函数CAN模块消息发送CAN模块消息接收标识符筛选发送中断的事件源和回调函数 CubeMX项目设置…

matlab设置背景颜色

matlab默认的背景颜色是纯白RGB(255,255,255)&#xff0c;纯白太刺眼&#xff0c;看久了&#xff0c;眼睛会酸胀、疼痛&#xff0c;将其改成豆沙绿RGB(205,123,90)&#xff0c;或者给出浅绿色RGB(128,255,255), 颜色就会柔和很多&#xff0c;眼睛感觉更舒适。     下面介绍在…

java springboot 在测试类中声明临时Bean对象

上文 java springboot在当前测试类中添加临时属性 不影响application和其他范围 中 我们讲了怎么在测试类中设置临时属性 但是 如果我们想设置临时的Bean呢&#xff1f; 其实做过几个项目的人都会理解 我们很多功能 需要一些第三方bean才能完成 那么 我们可能存在需要用第三方b…

Java实现windows系统截图

Java提供了一种方便的方式来截取Windows系统的截图。这个过程通常需要使用Java的Robot类来模拟用户的鼠标和键盘输入操作。下面将介绍如何使用Java实现Windows系统截图。 步骤1&#xff1a;导入Robot和AWT包 Java提供了一个Robot类&#xff0c;它可以模拟用户的键盘和鼠标操作…

2015-2020年全国地区生产总值及一二三产构成数据总览,shp/excel格式

今天我们来整理了2015-2020全国地区生产总值及一二三产构成数据&#xff0c;数据格式为shpexcel格式&#xff0c;数据精度可达各区县。 另外&#xff0c;需要说明的是&#xff1a;由于统计年鉴指标调整&#xff0c;每一年的数据并非字段相同&#xff0c;字段详情请参考已下载数…