在对某些数据进行排序的时候,例如很简单的冒泡排序可以帮助我们实现整数的排列
那在对复杂情况进行排序时,C语言提供了一个很好用的函数qsort帮助我们进行排序
本文就qsort的功能及其实现进行讲解。
一、冒牌排序排列0 1 2 3 4 5 6 7 8 9
代码:
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
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;
}
}
}
}
void test_by_bubble()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print(arr, sz);
}
int main()
{
//实现升序
test_by_bubble();
}
我们上述所定义的函数,只能单一地实现对于整数的排序
观察C语言提供地qsort:
利用这个函数,我们可以试着排列一些复杂的数据,比如:结构体类型的数据:
下边的年龄、成绩也可以排序:
不难发现,qsort函数,确实可以排列较为复杂的数据。那就来分析,实现它。
二、分析qsort
回想上面的冒泡排序,我们传的参数为数组地址和一共排序多少个。
这里的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++;
}
}
void my_qsort(void* base, int num, int width, 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 (arr[j] > arr[j + 1])
if(cmp((char*)base+j*width, (char*)base + (j+1) * width) >0) //cmp是函数指针,带回来一个int型的数据 >0 就交换
{
//交换
swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
三、测试自己实现的my_qsort
通过名字排序结构体:
通过年龄:
通过分数:
附上代码:
#include<stdio.h>
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
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;
}
}
}
}
void test_by_bubble()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print(arr, sz);
}
//创建结构体数据类型进行排序
struct Stu
{
char name[20];
int age;
double score;
};
//实现刚才的冒泡排序
//通过名字排序(现在为升序)
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;
}
//通过成绩排序(现在为升序)
int cmp_by_score(const void* e1, const void* e2)
{
return (int)(((struct Stu*)e1)->score - ((struct Stu*)e2)->score);
}
void qsort_struct()
{
struct Stu arr[3] = { {"zhangsan",15,100.0},{"lisi",25,80.0},{"wangwu",20,59.9} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_by_name);
qsort(arr, sz, sizeof(arr[0]), cmp_by_age);
qsort(arr, sz, sizeof(arr[0]), cmp_by_score);
}
//--------------------------------------------------------------------------------------------------------------------------------下面自己实现
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++;
}
}
void my_qsort(void* base, int num, int width, 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 (arr[j] > arr[j + 1])
if(cmp((char*)base+j*width, (char*)base + (j+1) * width) >0) //cmp是函数指针,带回来一个int型的数据 >0 就交换
{
//交换
swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
void my_qsort_struct_test()
{
struct Stu arr[3] = { {"zhangsan",15,100.0},{"lisi",25,80.0},{"wangwu",20,59.9} };
int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), cmp_by_name);
my_qsort(arr, sz, sizeof(arr[0]), cmp_by_age);
my_qsort(arr, sz, sizeof(arr[0]), cmp_by_score);
}
int main()
{
//实现升序
my_qsort_struct_test();
return 0;
}
总结:
因为qsort可以对复杂类型的数据进行排序,所以它函数的形参类型为void*,在进行模拟实现时,要记得将其强制类型转化为char*再进行操作。
又因为以字节为操作,就需要多传一个形参width来记录比较的字节数
每次实现时默认都是升序的,如果需要降序排列,可将比较函数的返回值前后调换位置。
比如上述例子中,如果对年龄想要升序排列,可以将代码改为:
int cmp_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e2)->age - ((struct Stu*)e1)->age;
}
以上就是qsort函数的实现了。