运用qsort函数进行快排并使用C语言模拟qsort

qsort 函数的使用

       首先qsort函数是使用快速排序算法来进行排序的,下面我们打开官网来查看qsort是如何使用的。


这里有四个参数,首先base 是至待排序的数组的首元素的地址,num 是值这个数组的元素个数,size 是指每个元素的大小,最后是一个函数指针(用来比较两个元素的不同,其中这个函数需要有返回值,当返回值小于0时p1需要放在p2前面,等于0时p1和p2不用改变位置,当返回值大于0时,p1需要放在p2的后面)由此可见,这个函数需要我们自己去编写,然后通过函数指针来调用。

下面我们来看看qsort的实践效果:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>typedef struct Stu
{char name[20];int age;
}Stu;int cmp_array(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int cmp_stu_name(const void* p1, const void* p2)
{return strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);
}int cmp_stu_age(const void* p1, const void* p2)
{return ((Stu*)p1)->age - ((Stu*)p2)->age;
}void PrintArray(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}void PrintStu(Stu* s, int sz)
{for (int i = 0; i < sz; i++){printf("%s %d", s[i].name, s[i].age);printf("\n");}
}int main()
{Stu s[3] = { {"zhangsan",18},{"lisi",19},{"sunwu",15} };int sz = sizeof(s) / sizeof(s[0]);int arr[10] = { 4,8,5,7,9,6,2,0,1,3 };int sz2 = sizeof(arr) / sizeof(arr[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_name);PrintStu(s, sz);printf("\n");qsort(s, sz, sizeof(s[0]), cmp_stu_age);PrintStu(s, sz);printf("\n");qsort(arr, sz2, sizeof(arr[0]), cmp_array);PrintArray(arr, sz2);printf("\n");return 0;
}

使用C语言模拟qsort

       这里我们使用冒泡排序算法进行排序,使用C语言来模拟qsort函数。
       首先我们来回顾冒泡排序算法,有两个要点一个是排序的趟数,另一个是每一趟排序的次数。这里以升序为例:

void bubble_sort(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;}}}
}

然后来模拟qsort函数呢?首先qsort函数几乎对任何数据都可以排序,所以我们的bubble_sort函数要做出相应调整,然后设计形参呢?对任何数据进行排序,也就是说数据的类型和大小都是不确定的,这样的话,我们可以使用size_t来作为数据类型,用void来接收不同类型的指针,实在不会的,我们可以参考qsort 函数来设计的。

void
base 接收待排序的首元素的地址,size_t num 和 size_t size 来接收元素个数和元素大小,最后就是最重要的函数设计了。

void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))

设计好形参,我们来考虑一下函数的主体部分,首先趟数是不改变的,每趟的次数也不用改变,毕竟我们还是使用冒泡排序算法,这样的话,还有最后一个就是if这个判断语句,应为我们无法直接通过像上面一样对两个数进行直接比较,我们需要调用函数来进行比较,也就是compar函数。

那有个问题,我们如何来写compar 函数的指针呢?这个指针不能大也不能小,否则就无法准确比较或者会产生越界行为,这样我们可以使用char* 为什么呢?首先我们需要两个两个数据来进行一一比较,这样我们需要知道准确的地址,必须是恰好指向每个元素的地址,而char 刚好就是一个字节,只要准确地进行指针加法运算就能得到这个元素地地址。

if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

还有个问题,我们怎么交换数据呢?其实和上面的理由差不多由于数据的类型不同,他们的大小也不同。这时我们可以使用char 因为char 是最小的数据类型了,也就是一个字节,无论数据是几个字节,都是char 的倍数也就是说都可以用一个字节的倍数来表示,这样的话,我们只需要知道数据类型的大小(size) 就可以来通过循环遍历来一个字节一个字节来进行进行交换就可以了,我们可以封装一个函数swap。

void swap(char* p1, char* p2, size_t size)
{int i = 0;while (i < size){char tmp = *(p1 + i);*(p1 + i) = *(p2 + i);*(p2 + i) = tmp;i++;}
}

那么我们最后得到的bubble_sort函数如下:

void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0){swap((char*)base + j * size, (char*)base + (j + 1) * size);}}}
}

我们来演练一下,看看效果是不是和qsort有着一样的效果:

代码如下:

#include <stdio.h>
#include <string.h>typedef struct Stu
{char name[20];int age;
}Stu;int cmp_array(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int cmp_stu_name(const void* p1, const void* p2)
{return strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);
}int cmp_stu_age(const void* p1, const void* p2)
{return ((Stu*)p1)->age - ((Stu*)p2)->age;
}void PrintArray(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}void PrintStu(Stu* s, int sz)
{for (int i = 0; i < sz; i++){printf("%s %d", s[i].name, s[i].age);printf("\n");}
}void swap(char* p1, char* p2, size_t size)
{int i = 0;while (i < size){char tmp = *(p1 + i);*(p1 + i) = *(p2 + i);*(p2 + i) = tmp;i++;}
}void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0){swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}int main()
{Stu s[3] = { {"zhangsan",18},{"lisi",19},{"sunwu",15} };int sz = sizeof(s) / sizeof(s[0]);int arr[10] = { 4,8,5,7,9,6,2,0,1,3 };int sz2 = sizeof(arr) / sizeof(arr[0]);bubble_sort(s, sz, sizeof(s[0]), cmp_stu_name);PrintStu(s, sz);printf("\n");bubble_sort(s, sz, sizeof(s[0]), cmp_stu_age);PrintStu(s, sz);printf("\n");bubble_sort(arr, sz2, sizeof(arr[0]), cmp_array);PrintArray(arr, sz2);printf("\n");return 0;
}

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

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

相关文章

JVM(6)

JMM JVM定义了一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果.在此之前,C/C直接使用物理硬件和操作系统的内存模型,因此,会由于不同平台下的内存模型差异,有可能导致程序在一套平台上并发完全正常,而在另…

Spring 事务传播机制

事务传播机制&#xff1a;多个事务⽅法存在调⽤关系时, 事务是如何在这些⽅法间进⾏传播的。 ⽐如&#xff1a;有两个⽅法A&#xff0c;B都被 Transactional 修饰,&#xff0c;A⽅法调⽤B⽅法 A⽅法运⾏时, 会开启⼀个事务。当A调⽤B时&#xff0c; B⽅法本⾝也有事务&#xf…

【CSS】(标准流部分)易忘知识点汇总

一、元素 块元素 常见的块元素&#xff1a; <h1>~<h6>、<p>、<div>、<ul>、<ol>、<li>行内元素 常见的行内元素&#xff1a; <a>、<strong>、<b>、<em>、<i>、<del>、<s>、<ins&…

Python实现DMI工具判断信号:股票技术分析的工具系列(3)

Python实现DMI工具判断信号&#xff1a;股票技术分析的工具系列&#xff08;3&#xff09; 介绍算法解释 代码rolling函数介绍完整代码 介绍 先看看官方介绍&#xff1a; DMI (趋向指标&#xff09; 用法 1.PDI线从下向上突破MDI线&#xff0c;显示有新多头进场&#xff0c;为…

喀秋莎软件如何编辑视频 Camtasia2023软件下载 电脑录屏剪辑软件推荐 Camtasia安装教程 微课视频制作方法 课件制作投屏软件

现在市面上的课件录制软件很多&#xff0c;许多人都听说过Camtasia&#xff0c;它是TechSmith旗下的一套专业屏幕录制软件&#xff0c;同时包含Camtasia录像器、Camtasia编辑器、Camtasia菜单制作器、Camtasia剧场、Camtasia播放器和Screencast的内置功能。 今天我们就来介绍如…

精准唇语同步:Wav2Lip 引领视频技术前沿 | 开源日报 No.188

Rudrabha/Wav2Lip Stars: 8.4k License: NOASSERTION Wav2Lip 是一个准确地在野外进行视频唇语同步的项目。 该项目的主要功能、关键特性和核心优势包括&#xff1a; 可以高精度地将视频与任何目标语音进行唇语同步适用于任何身份、声音和语言&#xff0c;也适用于 CGI 面孔和…

B树系列(详解)

目录 一、B-树 二、B树 三、B*树 四、时间复杂度 五、Mysql与B树系列 一、B-树 首先再说B树的性质以及其他的之前&#xff0c;先要说一声&#xff0c;好多人都把这个树叫B减树&#xff0c;其实不是&#xff0c;他就叫B树&#xff0c;至于原因我觉的没必要再这个名字上纠结…

基于Springboot的同城上门喂遛宠物系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的同城上门喂遛宠物系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

React Developer Tools带你掌握9个React组件调试技巧,十分钟学会

React Developer Tools 是 React 官方推出的开发者插件&#xff0c;可以毫不夸张的说&#xff0c;它在我们日常组件开发中&#xff0c;对于组件属性以及文件定位&#xff0c;props 排查等等场景都扮演者至关重要的角色&#xff1b;毋庸置疑&#xff0c;熟练使用React Developer…

Window下编写的sh文件在Linux/Docker中无法使用

Window下编写的sh文件在Linux/Docker中无法使用 一、sh文件目的1.1 初始状态1.2 目的 二、过程与异常2.1 首先获取标准ubuntu20.04 - 正常2.2 启动ubuntu20.04容器 - 正常2.3 执行windows下写的preInstall文件 - 报错 三、检查和处理3.1 评估异常3.2 处理异常3.3 调整后运行测试…

使用 frp 实现 windows 远程

前提条件&#xff1a; 拥有一台公网 ip 的服务器&#xff1b; 被远程控制的 windows 系统为专业版&#xff08;家庭版的其它方式没有尝试过&#xff09;&#xff1b; frp 下载包及使用说明 frp release 包的下载网址&#xff1a;https://github.com/fatedier/frp/releases 中…

浅析this指针

浅析this指针 文章目录 浅析this指针前言this指针作用this指针使用注意事项总结 前言 ​ 在面向对象的编程语言中&#xff0c;this指针是一个自引用指针&#xff0c;通常用于指向对象自身。通过这篇文章&#xff0c;我们将探讨this指针的核心特性、应用场景和相关案例。 this指…