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

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

相关文章:

C语言进阶之冒泡排序

✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 前情回顾 1、回调函数 2、冒泡排序 3、库函数qsort cmp&#xff08;sqort中的比较函数&#xff0c;需要我们自定义&#xff09; …...

零代码编程:用ChatGPT将SRT字幕文件批量转为Word文本文档

一个文件夹中有多个srt视频字幕文件&#xff0c;srt文件里面有很多时间轴&#xff1a; 现在想将其批量转为word文档&#xff0c;去掉里面与字符无关的时间轴&#xff0c;在ChatGPT中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个批量将SRT字幕文件转为…...

力扣刷题第二十六天--二叉树

前言 昨天看总决赛&#xff0c;差距太大&#xff0c;看的没意思&#xff0c;真的是一点变通没有啊。难受&#xff0c;没有写题的状态了。大概率是最后一次看比赛了&#xff0c;青春已复过&#xff0c;白日忽相催。召唤师要和生活对线了。英雄们的语音&#xff0c;台词&#xf…...

电脑显示msvcp140_1.dll丢失的5个常用解决方法,亲测可修复

常见于计算机操作中的"msvcp140_1.dll丢失"错误警示&#xff0c;往往令部分应用程序无法正常启动。为了解决这个问题&#xff0c;我们需要采取一些措施来修复丢失的文件。本文将介绍6个解决msvcp140_1.dll丢失的方法&#xff0c;帮助大家快速恢复计算机的正常运行。 …...

hive sql 行列转换 开窗函数 炸裂函数

hive sql 行列转换 开窗函数 炸裂函数 准备原始数据集 学生表 student.csv 讲师表 teacher.csv 课程表 course.csv 分数表 score.csv 员工表 emp.csv 雇员表 employee.csv 电影表 movie.txt 学生表 student.csv 001,彭于晏,1995-05-16,男 002,胡歌,1994-03-20,男 003,周杰伦,…...

Continuity” of stochastic integral wrt Brownian motion

See https://imathworks.com/math/math-continuity-of-stochastic-integral-wrt-brownian-motion/...

设置 wsl 桥接模式

一、环境要求 Win10/Win11 专业版&#xff0c;并已安装 Hyper-V 二、具体步骤 打开 Hyper-V 管理器 创建虚拟交换机 WSL Bridge 修改wsl配置文件 .wslconfig .wslconfig 文件所在路径如下&#xff1a; C:\Users\<UserName>\.wslconfig若 .wslconfig 文件不存在&am…...

[uni-app] uni.showToast 一闪而过问题/设定时间无效/1秒即逝

toast一闪就消失 1.猜测频繁点击导致 – 排除 2.猜测再定时器内导致-- 排除 3.和封装的接口调用一起导致 - 是改原因 深挖发现: axios封装中, 对loading/hindloading进行了配置, 看来是 showToast 与 loading等冲突导致的 wx.hideLoading(Object object) 解决办法 再封装的…...

7、信息打点——资产泄露CMS识别Git监控SVNDS_Store备份

知识点&#xff1a; CMS指纹识别、源码获取方式习惯&配置&特征等获取方式托管资产平台资源搜索监控 如何获取源码 直接识别CMS&#xff0c;根据CMS获取网站源码。CMS直接识别工具&#xff1a;云悉指纹识别平台。识别不了CMS&#xff0c;则通过以下方式获取源码&…...

【运维篇】5.6 Redis server 主从复制配置

文章目录 0. 前言1. 配置方式步骤1: 准备硬件和网络步骤2: 安装Redis步骤3: 配置主服务器的Redis步骤4: 配置从服务器的Redis步骤5: 测试复制功能步骤6: 监控复制状态 2. 参考文档 0. 前言 在Redis运维篇的第5.6章节中&#xff0c;将讨论Redis服务器的主从复制配置。在开始之前…...

Hive语法,函数--学习笔记

1&#xff0c;排序处理 1.1cluster by排序 &#xff0c;在Hive中使用order by排序时是全表扫描&#xff0c;且仅使用一个Reduce完成。 在海量数据待排序查询处理时&#xff0c;可以采用【先分桶再排序】的策略提升效率。此时&#xff0c; 就可以使用cluster by语法。 cluster…...

LeetCode热题100——动态规划

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

初识树(c语言)

树 定义&#xff1a;树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 有一个特殊的结点&#xff0c;称为根结点&#xff0c;根节点没有前驱结点 除根节点外&#xff0c;其余结点被分成M(M>0)个互不相交…...

听GPT 讲Rust源代码--src/librustdoc(2)

题图来自 Chromium项目将支持Rust编程语言[1] File: rust/src/librustdoc/html/render/search_index.rs 在Rust源代码中&#xff0c;rust/src/librustdoc/html/render/search_index.rs文件的作用是生成搜索索引&#xff0c;用于在Rust文档页面上进行关键字搜索。该文件实现了一…...

多目标应用:基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度(MATLAB)

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、基于非支配排序的蜣螂优化算法NSDBO 基于非支配排序的蜣螂优化算法NSDBO简介&#xff1a; https://blog.csdn.net/weixin46204734/article/details/128…...

泉盛UV-K5/K6全功能中文固件

https://github.com/wu58430/uv-k5-firmware-chinese/releases 主要功能&#xff1a; 中文菜单 许多来自 OneOfEleven 的模块&#xff1a; AM 修复&#xff0c;显著提高接收质量长按按钮执行 F 操作的功能复制快速扫描菜单中的频道名称编辑频道名称 频率显示选项扫描列表分配…...

基于JPBC的无证书聚合签名方案实现

基于JPBC的无证书聚合签名方案实现 摘要 一开始签名方案是基于PKI的&#xff0c;无证书签名起源于 基于身份密码体制&#xff0c; 2009 年第一篇无证书签名方案1被提出&#xff0c;随后出现了一些列方案2,3;包括无配对的无证书聚合签名方案4,更多内容参考文献5. 暂时没有看见…...

FreeRTOS内存管理分析

目录 heap_1.c内存管理算法 heap_2.c内存管理算法 heap_3.c内存管理算法 heap_4.c内存管理算法 heap_5.c内存管理算法 内存管理对应用程序和操作系统来说非常重要&#xff0c;而内存对于嵌入式系统来说是寸土寸金的资源&#xff0c;FreeRTOS操作系统将内核与内存管理分开实…...

hashMap索引原理

平日里面经常使用map这种数据结构&#xff0c;令人称奇的是他的访问速度为什么那么快&#xff1f;为什么可以通过key以接近O(1)的速度查找&#xff1f; 一、基础数据结构特点分析 1.1数组 查找的时间复杂度为O(1) 插入时间复杂度为O(n) 1.2链表 查找的时间复杂度为O(n) 插…...

qcow2、raw、vmdk等镜像格式工具

如果没有qemu&#xff0c;可以从这里下载安装&#xff1a;https://qemu.weilnetz.de/w64/...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...