qsort的使用与实现

news/2025/3/4 11:23:39/

 c语言常见的排序方法大概有这些,今天我们所讲的是就是qsort快排的讲解

 头文件

 qsort的使用

 我们先使用msdn查看他的相关资料,得知这个函数的传参请情况

 1.void *base

 翻译过来就是将要排序的函数的起始位置/数组首元素地址

2.size_t num 

 翻译过来就是数组个数(要注意这里的个数是指该数组元素的个数,单位是个)

3.size_t width 

 翻译过来就是每个元素大小(以字节计)

4. int (__cdecl *compare )(const void *elem1, const void *elem2 )

最后一个参数看起来很长,但实际看起来,他就是一个函数指针 ,我们看看在msdn上他的解释是什么

 compare                       elem1                                     elem2

[数] 比较函数              指向搜索键的指针                指向要与键进行比较的数组元素的指针

 经过阅读以上文章得知,compare函数的作用便是

compare( (void *) elem1, (void *) elem2 );

所以我们便不难实现compare函数 

返回类型为int   两个形参全都是void*

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

以上就是通过msdn查阅资料得知其功能,从而得知其的使用方法

以下排序展示效果

#include <stdio.h>
#include <stdlib.h>
int compare(const void* e1, const void* e2)
{return (*(int*)e1 - *(int*)e2);
}
int main()
{int arr[10] = { 8,5,2,3,6,4,1,7,9,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]),compare);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

代码运行起来便是如此效果

当然降序只需要将第四个参数的逻辑该反,具体就是如下

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

qsort排序结构体

上文的使用只在整形数组内使用了,但如果是结构体的话使用会不会又不同呢?

我们带着这个疑问,对上文的代码进行改进,使其可以对结构体排序;

#include <stdio.h>
#include<stdlib.h>
struct stu
{char name[20];int age;char sex[5];
};
int compare(const void* e1, const void* e2)
{return (*(int*)e1 - *(int*)e2);
}
int main()
{struct stu s[3] = { {"李四",20,"男"},{"王五",20,"男"} ,{"赵四",20,"男"} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]),compare);int i = 0; for (i = 0; i < sz; i++){printf("%s %d %s\n", s[i].name, s[i].age, s[i].sex);}return 0;
}

貌似也是可以行的通的,但是思考过后,发现我们是以什么方式排序的呢?我们没有修改第四个形参的函数的内部修改,第四个形参的作用就意在说明我们是利用什么方式在排序,(结构体以名字排序)那么我们就对于不同的类型要使用不同的compare,

以下代码 便是compare 通过name

#include<string.h>
int com_name(const void* e1, const void* e2)
{return (strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name));
}//这里一定要记得强制类型转换

qsort的实现(排序整形)

 qsort我们会用以后,那么就要去尝试着怎么自己实现,

我们先看以下冒泡排序的实现方法

void Bubble_sort(int arr[], int size)//int arr[]等价于int *arr
{int j, i;for (i = 0; i < size - 1; i++)//size-1是因为不用与自己比较,所以比的数就少一个{int count = 0;for (j = 0; j < size - 1 - i; j++)	//size-1-i是因为每一趟就会少一个数比较{if (arr[j] > arr[j + 1])//这是升序排法,前一个数和后一个数比较,如果前数大则与后一个数换位置{int tem = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tem;count = 1;}}if (count == 0)			//如果某一趟没有交换位置,则说明已经排好序,直接退出循环break;}
}
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int i = 0;Bubble_sort(arr, 10);for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

 所标红的地方便是相当于qsort里面第四个参数(比较),我们在冒泡排序实现代码基础上进行修改

对于实现者:不知道排序的是什么类型的数组
对于使用者:知道其排序的是什么类型的数组
所以使用去qsort最重要的是对于不同类型使用的com(第四个参数)是不同的

对于第一个参数

msdn上是void*类型的,void*类型的好处就是可以接受任何类型的地址,利用这一点就可以排序任何类型的数组

对于第二个参数跟冒泡排序的参数sz一样,第三个参数与第一个参数结合,不就是解释了每个元素大小(把第一个参数强制类型转化为char*)(也大致就了解是什么类型)达到了冒泡排序第一个参数作用

修改参数:

void Bubble_sort(void* base, size_t num, size_t width, int (*com)(const void* e1, const void* e2)
)

大致思路路就是

 com(比较大小)

 

if (com((char*)base + j * width, (char*)base + (j + 1) * width)>0)int com(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}

swap(交换)

 

swap((char*)base + j * width, (char*)base + (j + 1) * width, width);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++;}
}

总结

 

#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 com(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void Bubble_sort(void* base,size_t num,size_t width,int (*com)(const void* e1, const void* e2))
{int j, i;for (i = 0; i < num - 1; i++){int count = 0;for (j = 0; j < num - 1 - i; j++){if (com((char*)base + j * width, (char*)base + (j + 1) * width)>0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}	
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);Bubble_sort(arr, sz, sizeof(arr[0]), com);for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

 

 排序结构体的数组只需要改变com函数即可


http://www.ppmy.cn/news/1368172.html

相关文章

前端sql条件拼接js工具

因为项目原因&#xff0c;需要前端写sql&#xff0c;所以弄了一套sql条件拼接的js工具 ​ /*常量 LT : " < ", LE : " < ", GT : " > ", GE : " > ", NE : " ! ", EQ : " ", LIKE : " like &qu…

[渗透教程]-013-嗅探工具-wireshark操作

文章目录 tor下载wireshark抓包类型启动场景实战tor下载 tor下载链接 zlibary暗网地址 2681506@gmail.com YanErrol123@wireshark Wireshark是网络封包分析软件,可以抓包.可以 使用winpcap与网卡直接进行数据交换.作用: 网络管理员使用wireshark来检测网络问题,网络工程师使用…

并查集学习: leetcode 2368. 受限条件下可到达节点的数目

现有一棵由 n 个节点组成的无向树&#xff0c;节点编号从 0 到 n - 1 &#xff0c;共有 n - 1 条边。 给你一个二维整数数组 edges &#xff0c;长度为 n - 1 &#xff0c;其中 edges[i] [ai, bi] 表示树中节点 ai 和 bi 之间存在一条边。另给你一个整数数组 restricted 表示…

三天学会阿里分布式事务框架Seata-seata事务日志mysql持久化配置

锋哥原创的分布式事务框架Seata视频教程&#xff1a; 实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;_哔哩哔哩_bilibili实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;共计10条视频&…

【LeetCode每日一题】【BFS模版与例题】863.二叉树中所有距离为 K 的结点

BFS的基本概念 BFS 是广度优先搜索&#xff08;Breadth-First Search&#xff09;的缩写&#xff0c;是一种图遍历算法。它从给定的起始节点开始&#xff0c;逐层遍历图中的节点&#xff0c;直到遍历到目标节点或者遍历完所有可达节点。 BFS 算法的核心思想是先访问当前节点的…

【亚马逊云科技】通过Amazon CloudFront(CDN)快速访问资源

文章目录 前言一、应用场景二、【亚马逊云科技】CloudFront&#xff08;CDN&#xff09;的优势三、入门使用总结 前言 前面有篇文章我们介绍了亚马逊云科技的云存储服务。云存储服务主要用于托管资源&#xff0c;而本篇文章要介绍的CDN则是一种对托管资源的快速访问服务&#…

[⑥5G NR]: 无线接口协议,信道映射学习

5G系统整体包括核心网、接入网以及终端部分&#xff0c;接入网与终端间通过无线空口协议栈进行连接。无线接口可分为三个协议层&#xff1a;物理层&#xff08;L1&#xff09;、数据链路层&#xff08;L2&#xff09;和网络层&#xff08;L3&#xff09;。 L1&#xff1a;物理…

Pytorch学习 day02(加载数据)

加载数据 * Dataset提供一种方式&#xff1a;来获取数据及其label&#xff0c;给数据进行编号 * Dataloader为神经网络提供不同的数据形式 Dataset的组织形式有很多种&#xff0c;例如&#xff1a; 将label放在文件夹名上&#xff0c;如下&#xff1a; #Dateset # --train #…