目录
前言
上文说到回调函数的使用,本文就应用回调函数实现快速排序吧!!!
一、冒泡排序
在上文已经写过Bubble_sort的函数,这里就不在讲解,直接上代码。
void bubble_sort(int arr[], int sz)
{
//冒泡排序的趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//一趟冒泡排序
int j = 0;
for (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;
}
}
}
}
二、快速排序的实现
1.qsort的底层逻辑
qsort 底层使用的快速排序
void qsort( void* base, //待排序数据的起始地址
size_t num, //待排序数据的元素个数
size_t size, //待排序数据的一个元素的大小,单位是字节
int (*cmp)(const void*, const void*)//函数指针 - 指向了一个比较函数,这个函数是用来比较2个元素的);
2.Bubble_sort的改进
仿照qsort的函数参数,我们可以知道实现的关键就是比较和交换这两部分。
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void*e2))
{
//冒泡排序的趟数
int i = 0;
for (i = 0; i < num - 1; i++)
{
//一趟冒泡排序
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
//比较......
{
//交换......
}
}
}
}
(1)比较的改进
如果想实现各种数据类型的排序,比较只用if (arr[j] > arr[j + 1]) 是远远不够的,比如遇到结构体的时候,该比较方法就不再适用了。这时我们可以换种思路,通过比较每一个字节来判断大小。此时就要用到函数指针了,也就是int (*cmp_type)(const void* e1, const void*e2),该函数需要使用者根据数据类型自行编写。然后在冒泡排序内部比较时调用该函数。为了逐个字节比较,可以使用(char*)base,强制转化为字符型指针,使每次后移时只移动一个字节。(char*)base + j * size为“第一个字节”的地址,所以“下一个字节”的地址为(char*)base + (j + 1) * size,这样Bubble_sort内比较部分需要传的参数就固定啦!
int (*cmp)(const void* e1, const void* e2)
e1是一个指针,存放了一个要比较的元素的地址
e2是一个指针,存放了一个要比较的元素的地址
e1指向的元素>e2指向的元素,返回>0的数字
e1指向的元素==e2指向的元素,返回0
e1指向的元素<e2指向的元素,返回<0的数字
//比较部分
if(cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)
下面就给出两种数据类型cmp函数吧
tips:void* 不可以比较大小哦!!!记得强制转换类型!!!
(一)整型
int cmp_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
(二)结构体类型
struct Stu
{
char name[20];//20个字节
int age; //4个字节
};
int cmp_stu_by_age(const void* e1, const void*e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_stu_by_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
(2) 交换的改进
既然比较是逐个字节比较,那交换也是如此,只不过要注意的是,需要把该数据完整的交换,所以与普通的交换函数相比,多了一个参数size,此时便能完整交换需要比较的数据。
这里选择用char*作为参数数据类型也正是因为它刚好能够达到交换一个字节的效果。
void swap(char* buf1, char* buf2, size_t size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
三.完整代码
int cmp_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
void swap(char* buf1, char* buf2, size_t size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void*e2))
{
//冒泡排序的趟数
int i = 0;
for (i = 0; i < num - 1; i++)
{
//一趟冒泡排序
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
//比较
if(cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)
{
//交换
swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}