文章目录
前言
关于qsort函数的学习总结,还望点个赞!
一、函数介绍
函数功能:快速排序
函数使用形式:
需要引用头文件: #include <stdlib.h>
void qsort( void *base, size_t num, size_t width, int ( *compare )(const void *elem1, const void *elem2 ) );
参数解释及为何使用
对于设计者:有以下几点未知
- 排序的元素类型及个数
- 排序的依据即如何比较
因此为了能使函数具备普遍性,因而设计了4个参数
对于第一个问题,设计了3个参数
-
void* base : void* 无类型指针用来存放任意类型的地址
-
size_t num : unsigned int num 用于存放元素个数
-
size_t width : unsigned int width 用于存放该类型元素的大小
对于第二个含数设计了1个参数 - 函数指针
- int (* compare) (const void * elem1, const void* elem2) 该参数为函数指针,用于存放比较函数(自定义)
- 返回值设为int 是因为规定结果被设计为 前’‘大‘’为 >0
相等为 = 0,后’‘大’'为 <0 - const细节:防止被比较的元素在函数内部被改变
- void* 同样是为了适应各种类型
二、使用举例
整型比较
代码如下(示例):
#include <stdlib.h>
int compare1(const void* e1, const void* e2)
{
//以int为例:对于无类型指针须转化为相应类型的指针
//因此用到强制类型转换
return *(int*)e1 - *(int*)e2;
}
void print(int arr[], int sz)
{
//打印
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main(void)
{
//排序整型
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);//求元素个数
qsort(arr, sz, sizeof(arr[0]), compare1);
print(arr, sz);
}
字符比较
浮点型比较
可类比整型
结构体比较
#include <stdlib.h>
struct stu
{
char name[20];
int age;
};
int sort_by_age(const void* e1, const void* e2)
{
//比年龄
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int sort_by_name(const void* e1, const void* e2)
{
//比name
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
void test2()
{
//排序结构体
struct stu s[] = { {"zhangsan", 30},{"lisi", 34},{"wangwu", 20} };
int sz = sizeof(s) / sizeof(s[0]);
//按照年龄来排序
qsort(s, sz, sizeof(s[0]), sort_by_age);
//按照名字来排序
qsort(s, sz, sizeof(s[0]), sort_by_name);
}
注意:
- (struct stu*)e1 对于这个要用括号括起来 即 ((struct stu*)e1) 再用 -> 去访问,不然报错
- struct stu 结构体的定义须放这些代码的最上面,不然报错
- strcmp 字符串比较函数,自左向右逐个按照ASCII码值进行比较,直到出现不同的字符或遇’\0’为止。不是比较长度,若比较长度用strlen求长度,再比大小
练习,模拟qsort函数的部分功能
模仿qsort函数实现一个冒泡排序的通用算法
void bubble_sort(void* base,
size_t sz,
size_t width,
int(* compare)(const void* e1, const void* e2))
{
int i = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//一趟排序
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
//不知道是什么类型,因此先转化只有1字节访问权限的char*,
//再加上 width * j - 即该类型所占字节大小
if (compare((char*)base+width*j,(char*)base+(j+1)*width) > 0)
{
swap((char*)base + width * j, (char*)base + (j + 1) * width,width);
}
}
}
}
void swap(char* e1, char* e2, int width)
{
//e1 与 e2 分别指向 对应元素的首字节的地址
//因此以1字节不断交换 width的大小,即可将两个元素交换
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *(e1);
*(e1) = *(e2);
*(e2) = tmp;
e1++;//char*指针+1走一个字节,指针不要
e2++;
}
}