qsort函数:
qsort函数是C语言stdlib.h头文件中所包含的库函数,原型是void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));使用该函数,可以做到对一些数据进行排序,比如给没有顺序的数字排序,那么,他的优势在哪里呢?我们学过冒泡排序,知道使用他可以简易的排列数据,qsort函数与冒泡排序有什么不同?我列出了一些qsort的优点供大家参考
现成的,可以排序任意类型的数据
比较两个整数的大小,< > =
比较两个字符串,strcmp
比较两个结构体数据 指定比较的标准
接下来,让我们来看看这个函数的使用方法
首先我们来看看qsort函数的参数设置
void qsort (
void* base,//要排序的对象
size_t num,//要排序的元素个数
size_t width,//宽度,即一个元素的大小,单位为字节
int(*cmp)(const void* e1, const void* e2)//qsort函数的使用者提供这个函数
);
其中后面的cmp是函数指针,它所表达的含义是指向一个函数并引用,也就是说,对数据排序的函数需要我们自己编译。
void* - 无具体类型的指针,所以他可以接受任何类型的地址,不能直接解引用操作,我们发现,比如冒泡排序的方法是无法排列字符型变量或结构体类型的变量,因为他们的类型不同,不适用于冒泡排序,但是在qsort函数中定义,我们可以传入任意类型的数据,也就是说他可以接受任何int,char,float等类型的变量,这就给了我们能排序任何类型的数据的“通行证”。
//冒泡排序
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;
}
}
}
}
在了解了qsort函数的参数定义后,我们来实现一下排列数据的代码
要使用qsort来排序整型数组,就要提供一个比较函数,这个比较函数能够比较2个整数的大小,因此我们定义一个简单的比较函数
int cmp_int(const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
完成后,我们可以再定义一个函数,用来定义要排序的数组和存放qsort和打印函数。
void test1()
{
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]), cmp_int);
print(arr,sz);
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//循环打印
}
printf("\n");
}
再用main函数调用就完成了
int main()
{
test1();
return 0;
}
是不是很简单?让我们运行试试
那我们再试试排列结构体类型?
也很简单,让我们先定义一个结构体变量
struct Stu
{
char name[20];
int age;
};
//接着,进行同样的操作:定义一个比较函数,这里拿年龄举例
int cmp_stu_by_age(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
接着定义函数使用qsort
void test2()
{
struct Stu s[] = { {"zhangsan",20},{"lisi",25},{"wangwu",50} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
int main()
{
test2();
return 0;
}
运行后发现可以排序
在知道qsort函数的定义和如何使用后,我们是否可以用冒泡排序来模拟实现qsort的功能?答案是肯定的,虽然在前面我们提到冒泡排序不能排列全部类型的数据,但是我们可以再定义一个函数swap,希望这个bubble_sort可以排序任意类型的数据,这样就可以达到目的,接着,我们再接受数据进行遍历排序,这个模拟qsort函数就实现了
void Swap(char* buf1, char* buf2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
//size_t是无符号整型,num是个数,个数不能是负数,width是宽度,即数据元素的字节大小
void bubble_sort(void* base,size_t num,size_t width,int (*cmp)(const void* p1,const void* p2))
{
size_t i = 0;
for (i = 0; i < num - 1; i++)
{
int flag = 1;//假设有序
//一趟排序的过程
size_t j = 0;
for (j = 0; j < num - 1; j++)
{
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
//转换为char类型,char*指针加一跳过一个字节
//j*width 跳过j*width个字节,width是宽度,相当于跳过j个元素
//int*跳过四个字节,不能判断结构体和char类型
flag = 0;
Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
}
}
if (flag == 1)
{
break;
}
}
}
void test3()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
void test4()
{
struct Stu s[] = { {"zhangsan",20},{"lisi",25},{"wangwu",50} };
int sz = sizeof(s) / sizeof(s[0]);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}
int main()
{
test3();
test4();
return 0;
}