基于冒泡排序思想的qsort函数的模拟实现

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary-walk

      ⸝⋆   ━━━┓
     - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━  ➴ ⷯ

本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。

👑💎💎👑💎💎👑 
💎💎💎自💎💎💎
💎💎💎信💎💎💎
👑💎💎 💎💎👑    希望在看完我的此篇博客后可以对你有帮助哟

👑👑💎💎💎👑👑   此外,希望各位大佬们在看完后,可以互赞互关一下,看到必回
👑👑👑💎👑👑👑

目录

一:冒泡排序的实现

二:qsort函数的简单介绍

三:基于冒泡排序思想的qsort函数的模拟实现


一:冒泡排序

首先我们需要先知道冒泡排序的核心是:两两相邻元素进行比较
冒泡排序的底层逻辑就是  双重for循环
1)外循环:需要进行9次比较对应代码

```c
for(int i = 0;i < sz - 1;i++)
```

2)内循环:一趟循环所需要比较的轮次

```c
for(int j = 0;j < sz-1-i;j++)
```

要求:对数组的各个数据按升序进行排列
首先我们先两两相邻元素进行比较
第一趟比较后对应结果:

对应核心代码:

```c
if (arr[j] > arr[j + 1])
{
    //交换
    tmp = arr[j];
    arr[j] = arr[j + 1];
    arr[j + 1] = tmp;
}
```

```cpp
  

void bubble(int arr[], int sz)
{
    for (int i = 0; i < sz - 1; i++)//确定总的趟数
    {
        for (int 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[] = { 1,4,7,8,5,2,9,6,3,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble(arr, sz);
return 0;
}


}
```
其实对于这个代码还有很多地方可以进行优化,使之变得更具有鲁棒性

> 比如说,当我们这一趟的数据已经是有序的,我们就不需要再次进行比较了,以此节省效率
优化之后的版本:


void bubble(int arr[], int sz)
{
    //确定sz 个元素对应的趟数;sz - 1
    for (int i = 0; i < sz - 1; i++)
    {
        //一趟冒泡排序的 执行
        int flag = 1;//假设一趟是有序的
        for (int 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;//直接终止循环,无需在进行排序,提高了效率
        }
    }
}
 二:qsort( )
1)qsort( )
void qsort (void* base,
            size_t num,
            size_t size,      
            int (*compar)(const void*,const void*));
参数介绍:
void*base:指向待排序的第一个元素的地址

size_t num:待排序元素的个数

size_t size:待排序的每一个元素的大小,单位字节

int (*compar)(const void*,const void*)) :函数指针,用来实现数据的排序,需要使用者自己                                                                    设计,注意这里参数类型不能改变

2)qsort( )简单应用

对整型数据排序:

int  cmp_int(const void* p1, const void* p2)
{
		//return (*p1 - *p2);//err 对于void* 类型的指针只能进行强转,之后在进行解引用或者是指针运算
	return (*(int*)p1 -  *(int*)p2);
}
void Print(int* parr, int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(parr + i));
	}
}
int main()
{
	int arr[] = { 7,4,1,8,5,2,9,6,3,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(int), cmp_int);
	Print(arr, sz);
	return 0;
	/*
	直接对void*类型的指针解引用出现:非法的间接寻址
	 对于void*类型的指针只能进行强转,之后在进行解引用或者是指针运算

	*/
}

 

 qsort()函数不是很牛吗,接下来看看对结构体类型数据排序如何?

对结构体类型数据进行排序:

struct Student
{
	char name[10];
	int age;
};
int cmp_by_name(const void* p1, const void* p2)
{
	//return (*(char*)p1 - *(char*)p2); //注意字符串比较不能直接相减,借助strcmp()函数
	//int strcmp ( const char * str1, const char * str2 );
	return strcmp ((char*)p1 , (char*)p2);
}
int main()
{
	/*int arr[] = { 7,4,1,8,5,2,9,6,3,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);*/
	struct Student arr1[] = { {"wisi,12"},{"langwu",14},{"zhangsan",13} };
	qsort(arr1, 3, sizeof(struct Student), cmp_by_name);
	return 0;
	/*
	直接对void*类型的指针解引用出现:非法的间接寻址
	 对于void*类型的指针只能进行强转,之后在进行解引用或者是指针运算

	*/
}

这是排序之前数组的内容: 

排序之后数组的内容:(注意是根据名字这个成员进行排序,也就是按对应位置的字母ASCII值进行比较

 

3)qsort( ) 借助冒泡排序思想的模拟实现 

思路的分析:

1)首先知道冒泡排序的核心:两两相邻元素进行比较

2)qsort( )各个参数意义:见文章上面介绍

3)void*类型指针应用的小注意

4)借助画图更易于理解

 以交换整型数据为例:

首先我们需要思考2个重要问题:

你有思绪了吗?没关系,接下来,我们一起来分析:

 对于问题1:

        我们需要借助一个函数指针,来实现对数据的比较;其次这里对指针的使用是有要求的,因为数据类型可以是任意的:int,long,float,结构体.......

那我们这里到底使用什么类型指针?

       毋庸置疑:char*  ,它是最小的,对他进行解引用是一个字节一个字节的,这样就会避免我们对指针访问不精确的问题

对应核心代码:注意这里我们假设以升序来排列

还是以整型数据来进行分析:

因为已经知道每个元素大小:width,

要比较的第一个元素地址已知

注意对 void* 类型指针不能直接用这里借助强转

下标为 j 对应地址   (char*)base + j * width

下标为 j + 1对应地址   (char*)base +( j+1) * width

 


			// 假设按升序来排序
			if (cmp_int((char*)base + j * width, (char*)base + (j + 1) * width) > 0)  //借助cmp_int来进行判断大小,需要把当前下标为j ,j+1 的地址传进去  ,重点是以什么类型指针来传进去
			
 问题2分析:

这里我们另写一个交换函数Swap( ) ,避免看起来复杂

  其实这个问题和上一个大同小异,既然是要交换元素,必然传地址,那么以什么类型指针接收呢?

显然是char*,同时我们还需要把这个要比较元素的大小传进来

 

对应核心代码:

void Swap( char* p1,  char* p2,int size) //注意这里必须把要比较每一个元素大小传来
{
	// 一个字节一个字节交换
	char tmp = 0;
	for (int i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		// p1,p2更新位置
		p1++, p2++;
	}
}
 对应完整代码:
int  cmp_int(const void* p1, const void* p2)
{
	//return (*p1 - *p2);//err 对于void* 类型的指针只能进行强转,之后在进行解引用或者是指针运算
	return (*(int*)p1 - *(int*)p2);
}
void Swap( char* p1,  char* p2,int size) //注意这里必须把要比较每一个元素大小传来
{
	// 一个字节一个字节交换
	char tmp = 0;
	for (int i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		// p1,p2更新位置
		p1++, p2++;
	}
}
void my_qsort(void* base, int num,int width,int (*cmp_int)(const void*,const void*))
{
	//借助冒泡进行排序
	for (int i = 0; i < num - 1; i++)  //确定趟数
	{
		for (int j = 0; j < num - 1 - i; j++)  //一趟的比较
		{
			// 假设按升序来排序
			if (cmp_int((char*)base + j * width, (char*)base + (j + 1) * width) > 0)  //借助cmp_int来进行判断大小,需要把当前下标为j ,j+1 的地址传进去  ,重点是以什么类型指针来传进去
			{
				// 进行交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);//把下标为j 和j+1的地址传进去
			}

		}
	}
}
int main()
{
	int arr[] = { 7,4,1,8,5,2,9,6,3,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//struct Student arr1[] = { {"wisi,12"},{"langwu",14},{"zhangsan",13} };
	my_qsort(arr, sz, sizeof(arr[0]), cmp_int);
	Print(arr, sz);
	return 0;
	/*
	直接对void*类型的指针解引用出现:非法的间接寻址
	 对于void*类型的指针只能进行强转,之后在进行解引用或者是指针运算

	*/
}

 

 接下来我们试一下看看对结构体类型的数据排序效果如何

 

 ok~~~以上就是今日要为大家分享的。要是觉得还不错的话,希望咱一波赞走起,给个关注,同时也蟹蟹各位大佬的支持,看到必回!!!

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

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

相关文章

基于JavaWeb+SSM+Vue家政项目微信小程序系统的设计和实现

基于JavaWebSSMVue家政项目微信小程序系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2…

c语言:用结构体找出学生年龄|练习题

一、题目 在结构体数组中&#xff0c;输入学生信息&#xff0c;找出学生的年龄。 如图&#xff1a; 二、代码图片【带注释】 三、源代码【带注释】 #include <stdio.h> //设置结构体&#xff0c;结构体有3个变量 struct student { int id; char name[20]; …

【计算机网络】TCP原理 | 可靠性机制分析(一)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

html5中各标签的语法格式总结以及属性值说明

有关闭标签的元素 a元素 <a href"" target"" title""></a>表格相关元素 table元素&#xff1a;表格标签caption元素&#xff1a;表头thead元素tbody元素&#xff1a;表格主体元素tfoot元素th元素tr元素&#xff1a;行标签td元素&…

P12 音视频复合流——TS流讲解

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

内存 vs 硬盘:固态硬盘代替内存可以工作吗?

使用固态硬盘代替内存可以吗&#xff1f; 答案是​&#xff1a;不可以​。 ​这个问题看似复杂&#xff0c;其实包含很多方面的原因。 一、存储结构方面 固态硬盘和内存在存储结构上就完全不同。 1.1 固态硬盘采用的是3D闪存单元阵列来存储数据 这些存储单元被一层层地堆…

keras,一个超酷的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - keras。 Github地址&#xff1a;https://github.com/keras-team/keras 深度学习已经成为解决各种复杂问题的有力工具&#xff0c;而 Python Keras 是…

基于ssm的智慧社区电子商务系统+vue论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

关于vite的glob坑

我先展示一段代码&#xff1a; /*** function 根据pages路径动态生成路由* param {Array} 基础路由*/ export default function (routes) {const modules import.meta.glob("../pages/**/page.js", { eager: true, import: "default" });const newRoutes…

windows系统安装docker(Hyper-V方式)

文章目录 1 环境准备2 下载3 安装4 替换国内镜像源5 修改镜像存储路径&#xff08;Hyepe-V方式&#xff09; 1 环境准备 ctrlshiftesc查看CPU的虚拟化是否启动 左键单击电脑左下角开始按钮—>点击“设置”—>搜索“Windows功能”—>启用或关闭Windows功能—>勾选H…

吴恩达倾情推荐!28张图全解深度学习知识!

本文约7500字&#xff0c;建议阅读15分钟本文将从深度学习基础&#xff08;01-13&#xff09;、卷积网络&#xff08;14-22&#xff09;和循环网络&#xff08;23-28&#xff09;三个方面介绍该笔记。 吴恩达在推特上展示了一份由 TessFerrandez 完成的深度学习专项课程图&…

JavaWeb 页面上显示中文乱码解决~

你们好&#xff0c;我是金金金。 场景 我正在学习servlet&#xff0c;通过write()方法向页面上写入中文数据&#xff0c;没想到显示的都是?? 乱码&#xff0c;如图 排查 很明显可以看出来页面上显示的是??&#xff0c;我猜想肯定是字符编码的问题&#xff0c;导致乱码 造成…

uniapp点击跳转传对象

目录 传对象传对象传送组件接受组件 最后 传对象 传对象 传送组件 点击传给组件 <view class"dki-tit-edit" click"gotificatedit(item)">编辑 </view>gotificatedit(item){console.log(item,item);let options JSON.stringify(item);uni.…

jetson AGC orin 配置pytorch和cuda使用、yolov8 TensorRt测试

文章目录 1、安装环境1.1、检查系统环境1.2、下载安装pytorch1.3、下载安装torchvision1.3、测试安装是否成功 2、yolov8测试2.1、官方python脚本测试2.2、tensorrt 模型转换2.3、tensorrt c 测试 1、安装环境 1.1、检查系统环境 检查系统环境、安装jetpack版本&#xff0c;执…

关于github最新登录方法

https://blog.csdn.net/freewzx2005/article/details/133956893 通过手机号验证&#xff0c;发现没有国内的手机号选项&#xff0c;尝试了修改网页的办法以及终端方式&#xff0c;都已经阻止了。 1.商店下载微软验证 2.扫描github上的二维码 大概几十秒钟就会刷新一次&#…

每天一杯羊奶,让身体更健康

每天一杯羊奶&#xff0c;让身体更健康 羊奶作为一种天然的健康饮品&#xff0c;越来越受到人们的关注和喜爱。它不仅口感醇厚&#xff0c;营养丰富&#xff0c;而且具有独特的保健功效。今天&#xff0c;小编羊大师带大家详细介绍一下每天喝一杯羊奶对身体的好处。 羊奶中的…

用Redis实现全局唯一ID

全局唯一ID 如果使用数据库自增ID就存在一些问题&#xff1a; id的规律性太明显受表数据量的限制 全局ID生成器&#xff0c;是一种在分布式系统下用来生成全局唯一ID的工具&#xff0c;一般要满足下列特性&#xff1a; 唯一性高可用递增性安全性高性能 为了增加ID的安全性…

看了致远OA的表单设计后的思考

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

x-cmd pkg | doggo - 现代化的 DNS 客户端

目录 简介首次用户快速实验指南功能特点类似工具与竞品进一步探索 简介 doggo 是一个由 Karan Sharma 于 2020 年使用 Go 语言开发的 DNS 客户端。它类似于 dig 命令&#xff0c;但旨在以现代化、简洁和可读的格式输出 DNS 查询结果。 首次用户快速实验指南 使用 x doggo 即可…

【Flink精讲】Flink数据延迟处理

面试题&#xff1a;Flink数据延迟怎么处理&#xff1f; 将迟到数据直接丢弃【默认方案】将迟到数据收集起来另外处理&#xff08;旁路输出&#xff09;重新激活已经关闭的窗口并重新计算以修正结果&#xff08;Lateness&#xff09; Flink数据延迟处理方案 用一个案例说明三…