qsort函数简单介绍
qsort函数C语言编译器函数库自带的排序函数。
是base所指数组进行排序。qsort函数包含在C 标准库 - <stdlib.h>中。
函数声明
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
参数
-
base-- 指向要排序的数组的第一个元素的指针。 -
nitems-- 由 base 指向的数组中元素的个数。 -
size-- 数组中每个元素的大小,以字节为单位。 -
compar-- 用来比较两个元素的函数,即函数指针(回调函数)
回调函数:
回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就说这是回调函数。
compar参数
compar参数指向一个比较两个元素的函数。比较函数的原型应该像下面这样。注意两个形参必须是const void *型,同时在调用compar 函数(compar实质为函数指针,这里称它所指向的函数也为compar)时,传入的实参也必须转换成const void *型。在compar函数内部会将const void *型转换成实际类型。
int compar(const void *p1, const void *p2);
如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的左面;
如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定;
如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的右面。
?模拟实现qsort函数
?这里我们用排int型举个简单例子
话不多说,直接上代码:
struct Stu
{
char name[20];
int age;
};
//比较两个int型变量大小
int cmp_int(const void*p1,const void*p2)
{
return *(int*)p1- *(int*)p2;
}
//比较名字
int cmp_by_name(const void*e1, const void*e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//比较年龄
int cmp_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age -((struct Stu*)e2)->age;
}
//进行交换
//这里为了对不同类型变量进行交换,我们用width变量来确定变量类型,以便更好交换
void Swap(char*p1, char* p2, size_t width)
{
char tmp;
int i = 0;
//这里我们逐字节交换
for (i = 0; i < width; i++)
{
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
//模拟qsort函数
void BubbleSort(void*base,size_t num,size_t width,int (*cmp)(const void*p1,const void*p2))
{
int i, j;
for (i = 0; i < num; i++)
{
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 );
}
}
}
}
//测试自定义的BubbleSort()
void test1()
{
int arr[] = { 1,3,5,7,4,2,6,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr,sz,sizeof(arr[0]),cmp_int);
for(int i=0;i<sz;i++)
{
printf("%d ", arr[i]);
}
}
void test2()
{
struct Stu s[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} };
int sz = sizeof(s) / sizeof(s[0]);
// 按照名字排序
BubbleSort(s, sz, sizeof(s[0]), cmp_by_name);
// 按照年龄来排序
BubbleSort(s, sz, sizeof(s[0]), cmp_by_age);
}
int main()
{
test1();
test2();
return 0;
}
那为什么需要进行逐字节交换呢?又为什么先强转char*呢?
? 因为不同的数据交换时所需要交换的字节数目不同,为了能够满足不同类型数据交换的要求,我们将每一种类型的数据都强转char*,再将所有数据逐字节交换.
|