qsort函数是C语言中的一个函数库函数,可以用来对不同类型的数组进行排序。
qsort函数有4个参数,分别是
1.被排序数组的数组名(首元素的地址)
2.数组中元素的个数(sizeof(arr)/sizeof(arr[0]))
3.数组中元素所占据的字节数,例如对一个float型数组,所占据的字节数就是sizeof(float)=4
4.第四个参数是一个函数指针,这个参数是特别重要的,这个函数指针的意义是告诉qsort函数我们的比较方式
代码如下(示例):
#include
#include
#include
typedef struct Stu
{/*结构体中的字符数组项不能省略长度*/
int age;
char names[20];
}Student;
int Cmpint(const void* p1, const void* p2)
{
/*这个函数的作用是比较2个元素的大小
用p1来接受第一个元素的地址,p2来接收第二个元素的地址
这里假设p1接收的是& arr[0],p2接收的是& arr[1]
如果* (int*)p1 > * (int*)p2, 就返回一个大于0的值
如果* (int*)p1 = *(int*)p2, 就返回一个等于0的值
如果* (int*)p1 < *(int*)p2, 就返回一个小于0的值*/
return *(int*)p1- *(int*)p2;
}
int Cmpfloat(const void* p1, const void* p2)
{
return (int)(*(float*)p1 - *(float*)p2);
}
int Cmpstructage(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int Cmpstructname(const void* p1, const void* p2)
{/*p1指向的值大于p2指向的值就返回正数,并且从小到大进行排序*/
return strcmp(((Student*)p1)->names,((Student*)p2)->names);
}
void test1()
{
int arr[] = { 1,3,5,6,9,6,63,6,52 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[1]), Cmpint);
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
void test2()
{
float b[] = {1.2,2.3,5.6,9.6,5.34,6.259,3.693 };
int i = 0;
qsort(b, sizeof(b) / sizeof(b[1]), sizeof(float), Cmpfloat);
for ( i = 0; i < sizeof(b) / sizeof(b[1]); i++)
{
printf("%f ", b[i]);
}
}
void test3()
{/*根据年龄排序*/
int i = 0;
struct Stu s[3] = { {25,"zhangsan"},{20,"lis"},{30,"wangwu"} };
qsort(s, sizeof(s) / sizeof(s[1]), sizeof(s[0]), Cmpstructage);
for ( i = 0; i < sizeof(s) / sizeof(s[1]); i++)
{
printf("%s ", s[i].names);
printf("%d\n", s[i].age);
}
}
void test4()
{
struct Stu student[3] = { {15,"zhang"},{13,"li"},{42,"buu"} };
qsort(student, sizeof(student) / sizeof(student[1]), sizeof(student[0]), Cmpstructname);
};
int main()
{
/*test1();*/
/*test2();*/
/*test3();*/
test4();
}
这里比较难以理解的就是第四个参数函数指针,下面的代码将简要说明该函数指针的意义
#define _CRT_SECURE_NO_WARNINGS
#include
#include
struct Stu
{
char names[20];
int age;
};
int cmpstruct_age(const void* m1, const void* m2)
{
return ((struct Stu*)m1)->age - ((struct Stu*)m2)->age;
}
int cmpstruct_name(const void* m1, const void* m2)
{
return strcmp(((struct Stu*)m1)->names, ((struct Stu*)m2)->names);
}
void swap(char* t1, char* t2, int width)
{
/*每一个元素大小是width个字节,char* 解引用指针访问一个字节
t1是首元素的开始地址,t2是下面一个元素的开始地址*/
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *(t1 + i);
*(t1 + i) = *(t2 + i);
*(t2 + i) = tmp;
}
}
int cmpint(const void* m1/*前面元素的起始位置*/, const void* m2/*下一个元素的起始位置*/)
{
return *((int*)m1) - *((int*)m2);
}
int cmpchar(const void* m1, const void* m2)
{
if (*(char*)m1> *(char*)m2)
{
return 1;
}
else
{
return 0;
}
}
void myqsort(void* dest/*首元素地址*/,int sz/*元素个数*/,int width,int(*cmp)(const void*,const void*))
{
/* (char*)dest + i*width是下标为i的元素的地址
|****|**** */
int i = 0;
for ( i = 0; i < sz; i++)/* sz个元素排序,下标为0~sz-1 */
{/*i=0,sz-1次比较。i=1,sz-2次比较*/
int j = 0;
for ( j = 0; j <sz-i-1; j++)
{
if (cmp((char*)dest + j * width, (char*)dest + (j +1)*width)>0)
{/*表示前面一个元素大于后面一个元素*/
swap((char*)dest + j * width, (char*)dest + (j + 1)*width,width);
}/*swap函数实现交换*/
}
}
}
int main()
{
/*int arr[10] = { 2,3,5,6,4,7,8,9,10,1 };
myqsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]),cmpint);*/
/*char arr[] = "asdfertgh";
myqsort(arr, strlen(arr), sizeof(arr[0]), cmpchar);*/
struct Stu s[4] = { {"zhangsan",10},{"lisi",8},{"wangwu",12},{"tom",9} };
myqsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmpstruct_name);
return 0;
}
qsort函数设计的巧妙之处在于它用void的指针来接受任意类型的数组的首元素地址,然后将其转化为char类型的指针,由于char*的指针进行解引用一次访问一个字节,配合第三个参数(数组中每个元素所占据的字节数)就可以实现一个字节一个字节的对数组中的内容进行更改,而不用去关心数组中的元素到底是什么类型。