当前位置:网站首页>【指针进阶三】实现C语言快排函数qsort&回调函数
【指针进阶三】实现C语言快排函数qsort&回调函数
2022-06-12 08:26:00 【每天都要坚持刷题】
0. 经典快速排序算法-Quick_sort
先来手动实现一下Quick_sort 排序函数
#include<stdio.h>
void Swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void Quick_sort(int* arr, int begin, int end)
{
if (begin >= end)
{
return;
}
int keyi = begin;
int left = begin, right = end;
while (left < right)
{
while (left < right && arr[right] >= arr[keyi])
{
right--;
}
while (left < right && arr[left] <= arr[keyi])
{
left++;
}
Swap(&arr[left], &arr[right]);
}
int meeti = left;
Swap(&arr[keyi], &arr[meeti]);
Quick_sort(arr, begin, meeti-1);
Quick_sort(arr, meeti+1, end);
}
void Print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d\t", arr[i]);
}
}
int main()
{
int arr[5] = { 12,43,5,23,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
Quick_sort(arr, 0,sz-1);
Print(arr, sz);
return 0;
}排序结果:
但是这里有一个问题: 如果下次我想对一个结构体进行排序,我对这个排序算法的改动就会非常大(几乎每一处都有改动),下面我也给出排序结构体相应的代码实现,给各位看看。
#include<stdio.h>
#include<string.h>
typedef struct stu
{
char name[20];
int age;
}stu;
void Swap(stu* a,stu* b)
{
stu temp = *a;
*a = *b;
*b = temp;
}
void Quick_sort(stu* ps, int begin, int end)
{
if (begin >= end)
{
return;
}
int keyi = begin;
int left = begin, right = end;
while (left < right)
{
while (left < right && strcmp(ps[right].name, ps[keyi].name) >= 0)
{
right--;
}
while (left < right && strcmp(ps[left].name, ps[keyi].name) <= 0)
{
left++;
}
Swap(&ps[left], &ps[right]);
}
int meeti = left;
Swap(&ps[keyi], &ps[meeti]);
Quick_sort(ps, begin, meeti - 1);
Quick_sort(ps, meeti+1, end);
}
void Print(stu* ps, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%s\n", ps[i].name);
}
}
int main()
{
stu s[3] = { {"张三",18},{"李四",20},{"王五",19} };
int sz = sizeof(s) / sizeof(s[0]);
Quick_sort(s,0,sz-1);
Print(s, sz);
return 0;
}排序结果:

由此我们就想:能不能设计出一个函数使得在给不同数据类型的元素进行排序时能够增加排序函数Quick_sort代码的复用性,因此,库函数qsort应运而生 ,那这个函数长什么样子呐?
1. qsort排序函数的基本介绍
qsort排序函数是C语言标准库里的函数,实现原理是快速排序算法,函数原型如下:

qsort函数的相关参数的介绍和意义:
- 头文件: #include<stdlib.h>
- 返回值: 无
- void base: 待排序数据元素的起始地址
- size_t num: 待排序数据元素的个数
- size_t width:待排序数据元素所占的大小,单位是字节
- int( * cmp)(const void*,const void*): 函数指针-比较数据元素大小的函数,排序依据
举个例子:
#include<stdio.h>
#include<stdlib.h>
//以qsort库函数实现整型数组排序为例
int main()
{
int arr[5] = { 12,43,5,23,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp);
//arr:数组名,也是数组首元素的地址,数值上等于首元素中4个字节中地址最低的那个字节的地址
//sz:数组arr的元素个数
//sizeof(arr[0]):每一个数组元素所占的字节数
//cmp_int:回调函数-比较数组元素的函数,根据调用者的需要自行实现
Print(arr, sz);
return 0;
}先抛去qsort函数具体实现不谈,看到这里,你就知道了qsort函数的灵活性在于第四个参数(比较函数)是可以根据使用者的具体排序要求来自行设计。
2. 比较函数
比较函数的设计举例:整型数组,结构体数组等等
整型数组排序:(全部代码)
担心你看花函数之间的调用关系:给你个图理解一下

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* e1, const void* e2)
{
//比较两个整型元素
//void*是无具体类型的指针
//void*的指针可以接收任意类型的地址,类似垃圾桶
//void*的指针没有具体类型,不能+1-1(因为不知道加多少)
//升序:
return *(int*)e1 - *(int*)e2;
//降序:
//return *(int*)e2 - *(int*)e1;
}
void Print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d\t", arr[i]);
}
}
void test1()
{
int arr[6] = { 14,35,4,42,6,12 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(&arr[0], sz, sizeof(arr[0]), cmp_int);
Print(arr, sz);
}
int main()
{
test1();
return 0;
}由于void空类型的指针:
- 可以接收任何类型的指针
- 不能直接加减整数,使用前需要强转
因为cmp比较函数需要使用者自行设计,所以对于不同的使用者在qsort函数里传给cmp函数的参数类型可能是任何类型的指针,所以在cmp比较函数内得用void*类型的指针来接收,使用时只需将void* 类型的指针做出相应的强转即可。
排序结果:

结构体数组排序:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct stu
{
char name[20];
int age;
}stu;
int cmp_struct_by_name(const void* e1, const void* e2)
{
return strcmp(((stu*)e1)->name, ((stu*)e2)->name);//妙哉之处
}
void Print(stu* ps, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%s\n", ps[i].name);
}
}
void test2()
{
stu s[3] = { {"zhangsan",18},{"lisi",20},{"wangwu",19} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s,sz,sizeof(s[0]),cmp_struct_by_name);
Print(s, sz);
}
int main()
{
test2();
return 0;
}排序结果:

比较字符串用strcmp函数,头文件#include<string.h>
- 妙哉之处:strcmp比较函数和规定的cmp比较函数的返回值的意义相同
- 返回值>0 elem1>elem2
- 返回值==0 elem1==elem2
- 返回值<0 elem1<elem2

2. qsort函数的具体实现
学习qsort函数的具体实现,你将学到这个C语言库函数另一个绝妙的地方。
void Swap(char* buff1,char* buff2,int width)
{
if (buff1 != buff2)
{
//way1
//while (width--)
//{
// char temp = *buff1;
// *buff1 = *buff2;
// *buff2 = temp;
// buff1++;
// buff2++;
//way2
for (int i = 0; i < width; i++)
{
char temp = *(buff1+i);
*(buff1+i) = *(buff2+i);
*(buff2+i) = temp;
}
}
}
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void*, const void*))
{
int flag = 1;
//趟数
for (int i = 0; i < sz-1; i++)
{
for (int j = 0; j < sz - 1 - i; j++)
{
if (cmp_struct_by_name((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;
}
}巧妙之处在于将实际参数void* 类型的base指针强转为char*类型。
类比int arr[5]={34,5,35,62,1};
Print(arr,5),这里的arr其实就是首元素的地址,在数值上和首元素4个字节中最低字节的地址是相同的,所以cmp函数的参数即使是char* 一个字节的地址,在cmp函数内同样可以强转为所需要的类型,进行解引用,拿到相应的字节数进行比较,这样就能做到在bubble_sort函数内得到统一,所以无论我们要对任何类型的数据进行排序,都可以直接调用bubble_sort函数,只需要更改cmp函数即可,这就增加了bubble_sort函数代码的复用性。
边栏推荐
- Py&GO编程技巧篇:逻辑控制避免if else
- Hands on deep learning -- image classification dataset fashion MNIST
- Asp Net project add log function
- Summary of 3D point cloud construction plane method
- 网站Colab与Kaggle
- What is the quality traceability function of MES system pursuing?
- Query in MySQL
- 三国杀周边--------猪国杀题解
- MATLAB image processing -- image transformation correction second-order fitting
- FDA reviewers say Moderna covid vaccine is safe and effective for children under 5 years of age
猜你喜欢

FDA reviewers say Moderna covid vaccine is safe and effective for children under 5 years of age

What is an extension method- What are Extension Methods?

MATLAB image processing - cosine noise removal in image (with code)

Ankerui fire emergency lighting and evacuation indication system

ctfshow web3

Scope of bean

(P36-P39)右值和右值引用、右值引用的作用以及使用、未定引用类型的推导、右值引用的传递

Discrete chapter I

(P19-P20)委托构造函数(代理构造函数)和继承构造函数(使用using)

How to write simple music program with MATLAB
随机推荐
Detailed explanation of Google open source sfmlearner paper combining in-depth learning slam -unsupervised learning of depth and ego motion from video
Hands on deep learning -- image classification dataset fashion MNIST
DUF:Deep Video Super-Resolution Network Using Dynamic Upsampling Filters ... Reading notes
Figure neural network makes Google maps more intelligent
What is the beauty of MES equipment management for enterprises?
MES帮助企业智能化改造,提高企业生产透明度
KAtex problem of vscade: parseerror: KAtex parse error: can't use function '$' in math mode at position
Webrtc adding third-party libraries
MYSQL中的查询
The Three Kingdoms kill the surrounding areas -------- explanation of the pig Kingdom kill problem
Vision Transformer | Arxiv 2205 - LiTv2: Fast Vision Transformers with HiLo Attention
Hands on learning and deep learning -- a brief introduction to softmax regression
企业上MES系统的驱动力来自哪里?选型又该注意哪些问题?
vm虛擬機中使用NAT模式特別說明
后MES系统的时代,已逐渐到来
牛客网的项目梳理
MATLAB image processing - Otsu threshold segmentation (with code)
APS软件有哪些排程规则?有何异常处理方案?
目前MES应用很多,为什么APS排程系统很少,原因何在?
(P19-P20)委托构造函数(代理构造函数)和继承构造函数(使用using)