模拟实现qsort()

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

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

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

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

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

时隔多日,重出江湖! 今日给大家 share  一个关于如何实现qsort()

目录


一· 前言

二.qsort()函数的介绍

三· 函数模拟实现

 

首先想要实现此函数的模拟,我们就必须先了解qsort()

1.qsort()函数介绍

函数返回值:

 看不懂,木有关系,接下来我逐一解释

 

void qsort (
void* base, 
size_t num, 
size_t size,
int (*compar)(const void*,const void*)
);

第一个参数void* base:指向要比较首元素的地址,注意因为不知道要比较数据的类型,所以这里是void*

第二个参数:size_t num,所比较数组的元素 个数

第三个参数:size_t size 每个元素 所占字节的大小

第四个参数:int (*compar)(const void*,const void*)  是一个函数指针,这是用户自己设计的一个函数,用来比较元素大小

 2.qsort()的初步使用

用此函数实现对数据的快速排序

数组:int arr[ ] = { 2,3,1,6,5,4,7,8,9,10 };

 思路:我们用户需要自己写一个函数来实现元素比较大小的

注意此函数的返回类型必须是int

其次我们需要传入2个指针

函数的形参必须是:(const void* p1, const void* p2)

完整版代码:

#include<stdio.h>
#include<stdlib.h>

int  cmp(const void* p1, const void* p2)
{
	return (*(int*)p1) - (*(int*)p2);//没有必要进行大小比较,直接做差即可
}
void Print(int arr[], int sz)
	{
	int i = 0;
	for(i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
}int main()
{
	int arr[] = { 2,3,1,6,5,4,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort( arr, sz, sizeof(int), cmp);
	//qsort()有4个参数:待排序数组首元素地址,待排序元素个数,每个元素的大小,函数的地址(函数指针)
	Print(arr, sz);
	return 0;
}
 3.模拟实现

这里我们借助冒泡排序的思想,来模拟实现

所以我们核心逻辑还是双层for循环

那么我们就需要考虑以下问题:

1)如何从指定的数据类型(int)来实现对任意数据类型的比较?

===》这里写成 void*

2)2相邻元素也不能直接进行比较,因为数据具体类型我们是未知的

===》这里我们借助函数指针来实现队任意数据类型比较

 注意对于void*类型指针不能直接解引用,也不能直接进行指针运算

这里我们强转成char*类型指针,可以一个字节一个字节进行比较

这里我们需要把下标为j所对应元素地址传过去:又因为每个数据所占字节我们已知:size

所以下标为 j 所对应元素地址:(char*)base + j * size

同上:下标为 j+1 所对应元素地址:(char*)base + (j+1) * size

void Qsort(void* base, int num, int size, int (*cmp)(const void* p1, const  void* p2))
{

	for (int i = 0; i < num-1; i++)//确定一共进行多少趟
	{
		//一趟排序 需要交换的对数
		for (int j = 0; j < num - 1 - i; j++)
		{
			//默认是按升序进行排列
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size ) > 0)//这里必须写上>0

			{
				//进行交换
				Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);//在这里必须把要比较元素大小传过去
			}
		}
	}
}

 接下来就是如何实现2元素交换?

这里我们是一个字节一个字节来进行交换的

 

 

void Swap(char* p1, char* p2, int size)
{
	//注意这里是一个字节一个字节进行交换
	/*
	char* tmp = NULL;
	for (int i = 0; i < size; i++)
	{
	      以下只是改变了指针的位置,并没有实现我数据 的交换,注意交换你本质是内容交换,所以需要先解引用
		tmp = p1;
		p1 = p2;
		p2 = tmp;
		p1++, p2++;
	}*/
	//正确代码
	char tmp = 0;
	for (int i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++, p2++;
	}
	

}

 

 qsort()完整版代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//                                   以冒泡排序的思想模拟实现 qsort快速排序   注意这里用户需要根据自己需要写一个比较函数
//需要解决以下 问题:1) 实现对各种数据类型的模拟        2)对于2个元素的交换不仅仅是int类型数据    


void Swap(char* p1, char* p2, int size)
{
	//注意这里是一个字节一个字节进行交换
	/*
	char* tmp = NULL;
	for (int i = 0; i < size; i++)
	{
	      以下只是改变了指针的位置,并没有实现我数据 的交换,注意交换你本质是内容交换,所以需要先解引用
		tmp = p1;
		p1 = p2;
		p2 = tmp;
		p1++, p2++;
	}*/
	//正确代码
	char tmp = 0;
	for (int i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++, p2++;
	}
	

}
void Qsort(void* base, int num, int size, int (*cmp)(const void* p1, const  void* p2))
{

	for (int i = 0; i < num-1; i++)//确定一共进行多少趟
	{
		//一趟排序 需要交换的对数
		for (int j = 0; j < num - 1 - i; j++)
		{
			//默认是按升序进行排列
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size ) > 0)//这里必须写上>0

			{
				//进行交换
				Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);//在这里必须把要比较元素大小传过去
			}
		}
	}
}

int  cmp(const void*p1, const  void*p2)//用户自己设计的
{
	return (*(int*)p1) - (*(int*)p2);
}
void Print(int* p, int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p++;
	}
}
int main()
{
	int arr[] = { 7,4,1,2,5,8,3,6,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Qsort(arr, sz, sizeof(arr[0]), cmp);
	Print(arr, sz);
  	return 0;
}

 运行结果:

 ok~~以上就是今日我要为各位老铁的分享,要是感觉还不错的话,点个赞,互关一下呗

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

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

相关文章

计算机网络第一章(计算机网络开篇)

目录 一.什么是计算机网络1.0 何为计算机网络1.1 什么是Internet?1.2 互联网与互连网1.3 互联网基础结构发展的三个阶段 二.什么是网络协议2.1 协议的三要素2.2 internet协议标准 三. 互联网的组成3.1 边缘部分3.11 端系统之间的通信 3.2 核心部分3.21 数据交换技术 四. 计算机…

物业管理服务预约小程序的效果如何

物业所涵盖的场景比较多&#xff0c;如小区住宅、办公楼、医院、度假区等&#xff0c;而所涵盖的业务也非常广&#xff0c;而在实际管理中&#xff0c;无论对外还是对内也存在一定难题&#xff1a; 1、品牌展示难、内部管理难 物业需求度比较广&#xff0c;设置跨区域也可以&…

STM32-HAL库09-CAN通讯(loopback模式)

一、所用材料&#xff1a; STM32F103C6T6最小系统板 STM32CUBEMX&#xff08;HAL库软件&#xff09; MDK5 串口调试助手 二、所学内容&#xff1a; 初步学习如何使用STM32的CAN通讯功能&#xff0c;在本章节主要达到板内CAN通讯的效果&#xff0c;即32发送CAN信息再在CAN接收…

华为ssl vpn配置案例

t先在命令行输入命令 v-gateway sslvpn interface GigabitEthernet1/0/2 private 打开在命令行建立的sslvpn名称 直接开网络权限最大的模式&#xff1a;网络扩展 建立用户完成后点击上面的应用&#xff1a; 用命令行加策略&#xff1a; security-policy default action p…

【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法NIO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

Revit 平面的圆弧,空间的椭圆弧

大家对Revit的空间曲线那么理解,如何用代码创建空间的椭圆弧,,上看是圆弧,正面看是椭圆? 直接放代码: Document doc = commandData.Application.ActiveUIDocument.Document; Autodesk.Revit.DB.XYZ center = new Autodesk.Revit.DB.XYZ(0, 0, 0); …

更安全的ssh协议与Gui图形化界面使用

目录 前言&#xff1a; 一.Gui图形化界面的使用 二.ssh协议 SSH的主要作用包括&#xff1a; 相比其他网络协议&#xff0c;SSH的优势包括&#xff1a; 三.idea集成Git 前言&#xff1a; 上一篇讲解了git的命令用法以及https协议&#xff0c;但是这个协议放在做团队项目的…

Redis中的Zset类型

目录 Zset的相关命令 zadd zrange zcard zcount zrevrange zrangebyscore zpopmax bzpopmax zpopmin和bzpopmin zrank zrevrank zscore zrem zremrangebyrank zremrangebyscore 操作集合间的命令 zinterstore和zunionstore 内部编码 Zset的应用场景 Zset表…

【Linux系统化学习】冯诺依曼体系结构 | 操作系统

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 冯诺依曼体系结构 组成介绍 CPU和内存 以使用微信发消息为例理解冯诺依曼体系结构 操作系统 冯诺依曼体系结构 随着世界上第一台计算机ENIAC&#xff08;埃尼阿克&#xff09;的…

多级缓存之缓存同步

缓存数据同步的常见方式有三种&#xff1a; 设置有效期&#xff1a;给缓存设置有效期&#xff0c;到期后自动删除。再次查询时更新 优势&#xff1a;简单、方便缺点&#xff1a;时效性差&#xff0c;缓存过期之前可能不一致场景&#xff1a;更新频率较低&#xff0c;时效性要…

粘性定位-最下面怎么出现留白

问题&#xff1a;出现了留白 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title…

Fiddler Everywhere for Mac:一款强大且实用的网络调试工具

Fiddler Everywhere是一款备受Mac用户喜爱的网络调试工具&#xff0c;它具有强大的功能和易用性。作为一款老牌抓包工具&#xff0c;Fiddler Everywhere在Mac平台上拥有广泛的应用场景&#xff0c;无论是Web开发、移动应用开发还是网络调试&#xff0c;它都能提供全面的解决方案…

Ubuntu 22.04源码安装cmake 3.27.7

安装参考博客是《ubuntu安装cmake》和《Ubuntu 安装CMake》。 https://cmake.org/download是cmake官网下载的网址。 sudo wget -c https://github.com/Kitware/CMake/releases/download/v3.27.7/cmake-3.27.7.tar.gz可以下载源码&#xff0c;最后显示‘cmake-3.27.7.tar.gz’…

ARM-Cortex_M3/M4处理器开发简介

一、关于ARM-Cortex_M4处理器 ARM-Cortex_M3和ARM-Cortex_M4处理器使用32位架构&#xff0c;寄存器组中的内部寄存器、数据通路以及总线接口都是32位的&#xff0c;两者均基于ARMv7-M架构。 1、 Cortex_M处理器使用的指令集架构&#xff08;ISA&#xff09;为Thumb ISA&…

lv11 嵌入式开发 ARM体系结构理论基础(寄存器)3

目录 1 寄存器 2 ARM寄存器 2.1 专用寄存器 1 寄存器 概念 寄存器是处理器内部的存储器&#xff0c;没有地址 作用 一般用于暂时存放参与运算的数据和运算结果 注&#xff1a;全局变量不应该存入寄存器&#xff0c;数量有限会占用寄存器资源&#xff0c;寄存器读…

算法秘籍-王一博 | 数据结构与算法

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&…

js将图片文件转为base64格式

/***图片文件转换成BASE64字符串&#xff0c;异步任务*param {File} file图片文件对象*return {String} BASE64字符串*/ const getBase64 (file: File) > new Promise((resolve: (url: string) > void, reject) > {const reader new FileReader();reader.onload ()…

C 语言 break和continue语句

C 语言 break和continue语句 我们在之前的教程中了解了循环。在本教程中&#xff0c;我们将在示例的帮助下学习使用break和继续语句。 C 语言 break break语句在遇到循环时将立即结束循环。其语法为&#xff1a; break;break语句几乎总是与if…else循环内的语句一起使用。 …

SpringBoot实现Excel导入导出

SpringBoot实现Excel导入导出 在我们平时工作中经常会遇到要操作Excel的功能&#xff0c;比如导出个用户信息或者订单信息的Excel报表。你肯定听说过 POI这个东西&#xff0c;可以实现。但是POI实现的API确实很麻烦&#xff0c;它需要写那种逐行解析的代码&#xff08;类似Xm…

MicroPython ESP32 RTC功能使用介绍

MicroPython ESP32 RTC功能使用介绍 &#x1f4cc;Micropython esp32官方文档介绍&#xff1a;https://docs.micropython.org/en/latest/esp32/quickref.html#real-time-clock-rtc&#x1f516;本示例基于Thonny平台开发。&#x1f33f;使用ESP32S3开发板测试。✨所使用的固件版…