模拟实现库函数qsort - 冒泡排序 - C语言
库函数qsort的简单介绍
函数功能
库函数qsort(quick sort)基于八大排序算法中的快速排序,能够排序任意数据类型的数组其中包括整型,浮点型,字符串甚至还有自定义的结构体类型。
函数返回类型及函数参数
返回类型:void - 无返回值。
函数参数:
- void* base - 待排序数据的的起始地址。
- size_t num - 待排序数据中的元素个数。
- size_t width - 数据元素占内存空间大小,单位是字节。
- int (__cdecl *compare )(const void *elem1, const void *elem2 ) - 函数指针,指向一个比较两个元素大小的函数compare。
比较函数compare
比较函数需要用户自定义。
比较函数使得qsort通用性更好,有了比较函数,qsort可以实现对整型、浮点型、字符串、结构体等任意类型进行升序或降序排序。
int compare(const void* elem1, const void* elem2)
返回类型:int 类型
函数参数:const void* elem1, const void* elem2 - 两个const修饰的无类型指针,用来接收待比较的两个元素。
头文件
头文件:<stdlib.h>
模拟实现qsort - bubble_sort
在对库函数qsort有了一些了解之后,我们就要开始尝试用冒泡排序算法模拟实现qsort,即bubble_sort。
函数bubble_sort
函数swap用以交换两个元素,放在bubble_sort函数之前,方便bubble_sort函数调用。
void swap(char* buf1, char* buf2, size_t width)//交换两个元素
{
//参数:1.两个待交换元素的首地址 2.元素占内存空间大小,单位是字节
//基本算法:交换每个字节的数据
unsigned int i = 0;
for (i = 0; i < width; i++)
{
char temp = *buf1;//中间变量
*buf1 = *buf2;
*buf2 = temp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t width, int (*cmp)(const void* elem1,
const void* elem2))//冒泡排序模拟实现库函数qsort
{
unsigned int i = 0;//趟数
for (i = 0; i < num - 1; i++)
{
//排序一趟
unsigned int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
//调用比较函数
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)
> 0)
{
//交换两个元素
swap((char*)base + j * width, (char*)base + (j + 1) *
width, width);
}
}
}
}
以上就是函数bubble_sort的全部代码,我们知道,该函数可以排序任意类型,所以我们搭建了几种函数环境用以测试函数bubble_sort的运行情况。
测试函数运行情况
整型test_int
int cmp_int(const void* elem1, const void* elem2)//比较整型元素大小
{
return *(int*)elem1 - *(int*)elem2;//返回两个元素的差
}
void print_int(int arr[], unsigned int sz)//打印整型数组
{
unsigned int i = 0;
for (i = 0; i < sz; i++)//遍历数组
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test_int()//整型测试环境
{
int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
unsigned int sz = sizeof(arr) / sizeof(arr[0]);
print_int(arr, sz);//排序前打印
bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);//调用函数排序
print_int(arr, sz);//排序后打印
}
运行结果:
浮点型test_doubble
int cmp_double(const void* elem1, const void* elem2)//比较两个浮点型大小
{
return (int)(*(double*)elem1 - *(double*)elem2);//返回两个元素的差值
}
void print_double(double arr[], unsigned int sz)//打印浮点型数组
{
unsigned int i = 0;
for (i = 0; i < sz; i++)
{
printf("%.2lf ", arr[i]);
}
printf("\n");
}
void test_double()//整型测试环境
{
double arr[] = { 1.0,3.0,5.0,7.0,9.0,2.0,4.0,6.0,8.0,0.0 };
unsigned int sz = sizeof(arr) / sizeof(arr[0]);
print_double(arr, sz);//排序前打印
bubble_sort(arr, sz, sizeof(arr[0]), cmp_double);//调用函数排序
print_double(arr, sz);//排序后打印
}
运行结果:
字符型test_char
int cmp_char(const void* elem1, const void* elem2)//比较字符大小
{
return *(char*)elem1 - *(char*)elem2;
}
void print_char(char ch[], unsigned int sz)//打印字符型数组
{
unsigned int i = 0;
for (i = 0; i < sz; i++)
{
printf("%c ", ch[i]);
}
printf("\n");
}
void test_char()//字符型测试环境
{
char ch[] = { 'd','e','a','k','h','g','t','b' };
unsigned int sz = sizeof(ch) / sizeof(ch[0]);
print_char(ch, sz);//排序前打印
bubble_sort(ch, sz, sizeof(ch[0]), cmp_char);//调用函数
print_char(ch, sz);//排序后打印
}
运行结果:
结构体类型test_struct
结构体类型排序需要指定一个排序标准。
int cmp_struct_name_strlen(const void* elem1, const void* elem2)//比较名字长度大小
{
return (strlen(((struct Stu*)elem1)->name) - strlen(((struct
Stu*)elem2)->name));
}
int cmp_struct_name_strcmp(const void* elem1, const void* elem2)//比较名字首字母大小
{
return strcmp(((struct Stu*)elem1)->name, ((struct Stu*)elem2)->name);
}
int cmp_struct_age(const void* elem1, const void* elem2)//比较年龄大小
{
return (*(int*)elem1 - *(int*)elem2);
}
void print_struct(struct Stu stu[], unsigned int sz)//打印结构体类型数组
{
unsigned int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s %d ", stu[i].name, stu[i].age);
}
printf("\n");
}
void test_struct()//结构体类型测试环境
{
struct Stu stu[] = { {"zhangsan",38},{"qiansi",45},{"wangwu",30} };
unsigned int sz = sizeof(stu) / sizeof(stu[0]);
print_struct(stu, sz);//排序前打印
bubble_sort(stu, sz, sizeof(stu[0]), cmp_struct_name_strlen);//根据名字长度排序
print_struct(stu, sz);//名字长度排序后打印
//bubble_sort(stu, sz, sizeof(stu[0]), cmp_struct_name_strcmp);//根据名字首字母排序
//print_struct(stu, sz);//名字首字母排序后打印
//bubble_sort(stu, sz, sizeof(stu[0]), cmp_struct_age);//根据年龄排序
//print_struct(stu, sz);//年龄排序后打印
}
运行结果:
根据名字长度排序:
根据名字首字母排序:
根据年龄排序:
以上就是我们对几种不同类型的数组进行的排序测试,从运行结果可见函数实现的很成功。
注:本次测试均采用升序测试,若需降序,只需将比较函数中return语句内的两个变量交换位置即可。
总而言之,qsort函数实现对不同元素的排序主要就是通过对compare函数进行定义实现的,我们的bubble_sort函数也是如此,对于每一种变量类型的排序,我们都需要重新实现一种compare函数。但即便如此,qsort函数也极大地方便了程序员们。
到这里,我们对库函数qsort的模拟就结束了,你学会了吗!